Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>toFormatter(this, colorize); } /** * Initialize the compiler options. Only necessary if you're not doing * a normal compile() job. */ public void initOptions(CompilerOptions options) { this.options = options; if (errorManager == null) { if (outStream == null) { setErrorManager( new LoggerErrorManager(createMessageFormatter(), logger)); } else { PrintStreamErrorManager printer = new PrintStreamErrorManager(createMessageFormatter(), outStream); printer.setSummaryDetailLevel(options.summaryDetailLevel); setErrorManager(printer); } } } /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSSourceFile[] inputs, CompilerOptions options) { initOptions(options); } this.inputs = getAllInputsFromModules(); initBasedOnOptions(); initInputsByNameMap(); } /** * Do any initialization that is dependent on the compiler options. */ private void initBasedOnOptions() { // Create the source map if necessary. if (options.sourceMapOutputPath != null) { sourceMap = new SourceMap(); } } private CompilerInput[] makeCompilerInput( JSSourceFile[] files, boolean isExtern) { CompilerInput [] inputs = new CompilerInput[files.length]; for (int i = 0; i < files.length; ++i) { inputs[i] = new CompilerInput(files[i], isExtern); } return inputs; } private static final DiagnosticType EMPTY_MODULE_LIST_ERROR = DiagnosticType.error("JSC_EMPTY_MODULE_LIST_ERROR", "At least one module must be provided"); private static final DiagnosticType EMPTY_ROOT_MODULE_ERROR = } /** * Builds a single list of all module inputs. Verifies that it contains no * duplicates. */ private CompilerInput[] getAllInputsFromModules() { List<CompilerInput> inputs = new ArrayList<CompilerInput>(); Map<String, JSModule> inputMap = new HashMap<String, JSModule>(); for (JSModule module : modules) { for (CompilerInput input : module.getInputs()) { String inputName = input

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>.getName(); JSModule firstModule = inputMap.get(inputName); if (firstModule == null) { inputs.add(input); inputMap.put(inputName, module); } else { report(JSError.make(DUPLICATE_INPUT_IN_MODULES, firstModule.getName(), module.getName(), inputName)); } } } if (hasErrors()) { // There's no reason to bother parsing the code. return new CompilerInput[0]; } return inputs.toArray(new CompilerInput[inputs.size()]); } static final DiagnosticType DUPLICATE_INPUT = DiagnosticType.error("JSC_DUPLICATE_INPUT", "Duplicate input: {0}"); static final DiagnosticType DUPLICATE_EXTERN_INPUT = DiagnosticType.error("JSC_DUPLICATE_EXTERN_INPUT", "Duplicate extern input: {0}"); /** * Creates a map to make looking up an input by name fast. Also checks for * duplicate inputs. */ void initInputsByNameMap() { inputsByName = new HashMap<String, CompilerInput>(); for (CompilerInput input : externs) { String name = input.getName(); if (!inputsByName.containsKey(name)) { inputsByName.put(name, input); } else { report(JSError.make(DUPLICATE_EXTERN_INPUT, name)); } } for (CompilerInput input : inputs) { String name = input.getName(); if (!inputsByName.containsKey(name)) { inputsByName.put(name, input); } else { report(JSError.make(DUPLICATE_INPUT, name)); } } } public Result compile( JSSourceFile extern, JSSourceFile input, CompilerOptions options) { return compile(extern, new JSSourceFile[] { input }, options); } public Result compile( JSSourceFile extern, JSSourceFile[] input, CompilerOptions options) { return compile(new JSSourceFile[] { extern }, input, options); } public Result compile( JSSourceFile extern, JSModule[] modules, CompilerOptions options) { return compile(new JSSourceFile[] { extern }, modules, options); } /** * Compiles

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>("parseInputs"); try { // Parse externs sources. externsRoot = new Node(Token.BLOCK); externsRoot.setIsSyntheticBlock(true); for (CompilerInput input : externs) { Node n = input.getAstRoot(this); if (hasErrors()) { return null; } externsRoot.addChildToBack(n); } for (CompilerInput input : inputs) { Node n = input.getAstRoot(this); if (hasErrors()) { return null; } // Inputs can have a null AST during initial parse. if (n == null) { continue; } if (devMode) { runSanityCheck(); if (hasErrors()) { return null; } } if (options.sourceMapOutputPath != null || options.nameReferenceReportPath != null) { // Annotate the nodes in the tree with information from the // input file. This information is used to construct the SourceMap. SourceInformationAnnotator sia = new SourceInformationAnnotator(input.getName()); NodeTraversal.traverse(this, n, sia); } jsRoot.addChildToBack(n); } externAndJsRoot = new Node(Token.BLOCK, externsRoot, jsRoot); externAndJsRoot.setIsSyntheticBlock(true); return externAndJsRoot; } finally { stopTracer(tracer, "parseInputs"); } } public Node parse(JSSourceFile file) { initCompilerOptionsIfTesting(); addToDebugLog("Parsing: " + file.getName()); return new JsAst(file).getAstRoot(this); } @Override Node parseSyntheticCode(String js) { CompilerInput input = new CompilerInput( JSSourceFile.fromCode(" [synthetic] ", js)); inputsByName.put(input.getName(), input); return input.getAstRoot(this); } void initCompilerOptionsIfTesting() { if (options == null) { // initialization for tests that don't initialize the compiler // by the normal mechanisms. initOptions(new CompilerOptions()); } } @Override Node parseSyntheticCode(String fileName, String js) { initCompilerOptions

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>IfTesting(); return parse(JSSourceFile.fromCode(fileName, js)); } Node parseTestCode(String js) { initCompilerOptionsIfTesting(); CompilerInput input = new CompilerInput( JSSourceFile.fromCode(" [testcode] ", js)); if (inputsByName == null) { inputsByName = Maps.newHashMap(); } inputsByName.put(input.getName(), input); return input.getAstRoot(this); } @Override ErrorReporter getDefaultErrorReporter() { return defaultErrorReporter; } //------------------------------------------------------------------------ // Convert back to source code //------------------------------------------------------------------------ /** * Converts the main parse tree back to js code. */ public String toSource() { return runInCompilerThread(new Callable<String>() { public String call() throws Exception { Tracer tracer = newTracer("toSource"); try { CodeBuilder cb = new CodeBuilder(); if (jsRoot != null) { int i = 0; for (Node scriptNode = jsRoot.getFirstChild(); scriptNode != null; scriptNode = scriptNode.getNext()) { toSource(cb, i++, scriptNode); } } return cb.toString(); } finally { stopTracer(tracer, "toSource"); } } }); } /** * Converts the parse tree for each input back to js code. */ public String[] toSourceArray() { return runInCompilerThread(new Callable<String[]>() { public String[] call() throws Exception { Tracer tracer = newTracer("toSourceArray"); try { int numInputs = inputs.length; String[] sources = new String[numInputs]; CodeBuilder cb = new CodeBuilder(); for (int i = 0; i < numInputs; i++) { Node scriptNode = inputs[i].getAstRoot(Compiler.this); cb.reset(); toSource(cb, i, scriptNode); sources[i] = cb.toString(); } return sources; } finally { stopTracer(tracer, "toSourceArray"); } } }); } /** * Converts the parse tree for a module back to js code. */ public String toSource(final JSModule module) {

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> return runInCompilerThread(new Callable<String>() { public String call() throws Exception { List<CompilerInput> inputs = module.getInputs(); int numInputs = inputs.size(); if (numInputs == 0) { return ""; } CodeBuilder cb = new CodeBuilder(); for (int i = 0; i < numInputs; i++) { Node scriptNode = inputs.get(i).getAstRoot(Compiler.this); if (scriptNode == null) { throw new IllegalArgumentException( "Bad module: " + module.getName()); } toSource(cb, i, scriptNode); } return cb.toString(); } }); } /** * Converts the parse tree for each input in a module back to js code. */ public String[] toSourceArray(final JSModule module) { return runInCompilerThread(new Callable<String[]>() { public String[] call() throws Exception { List<CompilerInput> inputs = module.getInputs(); int numInputs = inputs.size(); if (numInputs == 0) { return new String[0]; } String[] sources = new String[numInputs]; CodeBuilder cb = new CodeBuilder(); for (int i = 0; i < numInputs; i++) { Node scriptNode = inputs.get(i).getAstRoot(Compiler.this); if (scriptNode == null) { throw new IllegalArgumentException( "Bad module input: " + inputs.get(i).getName()); } cb.reset(); toSource(cb, i, scriptNode); sources[i] = cb.toString(); } return sources; } }); } /** * Writes out js code from a root node. If printing input delimiters, this * method will attach a comment to the start of the text indicating which * input the output derived from. If there were any preserve annotations * within the root's source, they will also be printed in a block comment * at the beginning of the output. */ public void toSource(final CodeBuilder cb, final int inputSeqNum, final Node root) { runInCompilerThread(new Callable<Void>() { public Void call() throws Exception { if (options.printInputDelimiter

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> * For each target, we apply the target-specific defines by calling * {@code processDefines} and then {@code optimize} to optimize the AST * specifically for that target. */ public void processDefines() { (new DefaultPassConfig(options)).processDefines.create(this) .process(externsRoot, jsRoot); } boolean isInliningForbidden() { return options.propertyRenaming == PropertyRenamingPolicy.HEURISTIC || options.propertyRenaming == PropertyRenamingPolicy.AGGRESSIVE_HEURISTIC; } /** Control Flow Analysis. */ ControlFlowGraph<Node> computeCFG() { logger.info("Computing Control Flow Graph"); Tracer tracer = newTracer("computeCFG"); ControlFlowAnalysis cfa = new ControlFlowAnalysis(this, true); process(cfa); stopTracer(tracer, "computeCFG"); return cfa.getCfg(); } public void normalize() { logger.info("Normalizing"); startPass("normalize"); process(new Normalize(this, false)); setNormalized(); endPass(); } @Override void prepareAst(Node root) { Tracer tracer = newTracer("prepareAst"); CompilerPass pass = new PrepareAst(this); pass.process(null, root); stopTracer(tracer, "prepareAst"); } void recordFunctionInformation() { logger.info("Recording function information"); startPass("recordFunctionInformation"); RecordFunctionInformation recordFunctionInfoPass = new RecordFunctionInformation( this, getPassConfig().getIntermediateState().functionNames); process(recordFunctionInfoPass); functionInformationMap = recordFunctionInfoPass.getMap(); endPass(); } protected final CodeChangeHandler.RecentChange recentChange = new CodeChangeHandler.RecentChange(); private final List<CodeChangeHandler> codeChangeHandlers = Lists.<CodeChangeHandler>newArrayList(); @Override void addChangeHandler(CodeChangeHandler handler) { codeChangeHandlers.add(handler); } @Override void removeChangeHandler(CodeChangeHandler handler) { codeChangeHandlers.remove(handler); } /** * All passes should call reportCodeChange() when they alter * the JS tree structure. This is verified by CompilerTestCase. * This allows us to

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> int end = pos; int endLine = startLine; for (int n = 0; n < SOURCE_EXCERPT_REGION_LENGTH; n++, endLine++) { end = js.indexOf('\n', end); if (end == -1) { break; } end++; } if (lineNumber >= endLine) { return null; } if (end == -1) { int last = js.length() - 1; if (js.charAt(last) == '\n') { return new SimpleRegion(startLine, endLine, js.substring(pos, last)); } else { return new SimpleRegion(startLine, endLine, js.substring(pos)); } } else { return new SimpleRegion(startLine, endLine, js.substring(pos, end)); } } public static SourceFile fromFile(String fileName, Charset c) { return fromFile(new File(fileName), c); } public static SourceFile fromFile(String fileName) { return fromFile(new File(fileName)); } public static SourceFile fromFile(File file, Charset c) { return new OnDisk(file, c); } public static SourceFile fromFile(File file) { return new OnDisk(file); } public static SourceFile fromCode(String fileName, String code) { return new Preloaded(fileName, code); } public static SourceFile fromCode(String fileName, String originalPath, String code) { return new Preloaded(fileName, originalPath, code); } public static SourceFile fromInputStream(String fileName, InputStream s) throws IOException { return fromCode(fileName, CharStreams.toString(new InputStreamReader(s, Charsets.UTF_8))); } public static SourceFile fromInputStream(String fileName, String originalPath, InputStream s) throws IOException { return fromCode(fileName, originalPath, CharStreams.toString(new InputStreamReader(s, Charsets.UTF_8))); } public static SourceFile fromReader(String fileName, Reader r) throws IOException { return fromCode(fileName, CharStreams.toString(r)); } public static SourceFile fromGenerator(String fileName, Generator generator) { return new Generated

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>(String sourceName) { this.sourceName = sourceName; } public final int getEncodedSourceStart() { return encodedSourceStart; } public final int getEncodedSourceEnd() { return encodedSourceEnd; } public final void setEncodedSourceBounds(int start, int end) { this.encodedSourceStart = start; this.encodedSourceEnd = end; } public final int getBaseLineno() { return baseLineno; } public final void setBaseLineno(int lineno) { // One time action if (lineno < 0 || baseLineno >= 0) Kit.codeBug(); baseLineno = lineno; } public final int getEndLineno() { return endLineno; } public final void setEndLineno(int lineno) { // One time action if (lineno < 0 || endLineno >= 0) Kit.codeBug(); endLineno = lineno; } public final int getFunctionCount() { if (functions == null) { return 0; } return functions.size(); } public final FunctionNode getFunctionNode(int i) { return (FunctionNode)functions.get(i); } public final int addFunction(FunctionNode fnNode) { if (fnNode == null) Kit.codeBug(); if (functions == null) { functions = new ObjArray(); } functions.add(fnNode); return functions.size() - 1; } public final int getRegexpCount() { if (regexps == null) { return 0; } return regexps.size() / 2; } public final String getRegexpString(int index) { return (String)regexps.get(index * 2); } public final String getRegexpFlags(int index) { return (String)regexps.get(index * 2 + 1); } public final int addRegexp(String string, String flags) { if (string == null) Kit.codeBug(); if (regexps == null) { regexps = new ObjArray(); } regexps.add(string); regexps.add(flags); return regexps.size() / 2 - 1; } public final boolean hasParamOrVar

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>(String name) { return itsVariableNames.has(name); } public final int getParamOrVarIndex(String name) { return itsVariableNames.get(name, -1); } public final String getParamOrVarName(int index) { return (String)itsVariables.get(index); } public final int getParamCount() { return varStart; } public final int getParamAndVarCount() { return itsVariables.size(); } public final String[] getParamAndVarNames() { int N = itsVariables.size(); if (N == 0) { return ScriptRuntime.emptyStrings; } String[] array = new String[N]; itsVariables.toArray(array); return array; } public final boolean[] getParamAndVarConst() { int N = itsVariables.size(); boolean[] array = new boolean[N]; for (int i = 0; i < N; i++) if (itsConst.get(i) != null) array[i] = true; return array; } public final void addParam(String name) { // Check addparam is not called after addLocal if (varStart != itsVariables.size()) Kit.codeBug(); // Allow non-unique parameter names: use the last occurrence (parser // will warn about dups) int index = varStart++; itsVariables.add(name); itsConst.add(null); itsVariableNames.put(name, index); } public static final int NO_DUPLICATE = 1; public static final int DUPLICATE_VAR = 0; public static final int DUPLICATE_PARAMETER = -1; public static final int DUPLICATE_CONST = -2; /** * This function adds a variable to the set of var declarations for a * function (or script). This returns an indicator of a duplicate that * overrides a formal parameter (false if this dups a parameter). * @param name variable name * @return 1 if the name is not any form of duplicate, 0 if it duplicates a * non-parameter, -1 if it duplicates a parameter and -2 if it duplicates a * const. */ public final int

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> addVar(String name) { int vIndex = itsVariableNames.get(name, -1); if (vIndex != -1) { // There's already a variable or parameter with this name. if (vIndex >= varStart) { Object v = itsConst.get(vIndex); if (v != null) return DUPLICATE_CONST; else return DUPLICATE_VAR; } else return DUPLICATE_PARAMETER; } int index = itsVariables.size(); itsVariables.add(name); itsConst.add(null); itsVariableNames.put(name, index); return NO_DUPLICATE; } public final boolean addConst(String name) { int vIndex = itsVariableNames.get(name, -1); if (vIndex != -1) { // There's already a variable or parameter with this name. return false; } int index = itsVariables.size(); itsVariables.add(name); itsConst.add(name); itsVariableNames.put(name, index); return true; } public final void removeParamOrVar(String name) { int i = itsVariableNames.get(name, -1); if (i != -1) { itsVariables.remove(i); itsVariableNames.remove(name); ObjToIntMap.Iterator iter = itsVariableNames.newIterator(); for (iter.start(); !iter.done(); iter.next()) { int v = iter.getValue(); if (v > i) { iter.setValue(v - 1); } } } } public final Object getCompilerData() { return compilerData; } public final void setCompilerData(Object data) { if (data == null) throw new IllegalArgumentException(); // Can only call once if (compilerData != null) throw new IllegalStateException(); compilerData = data; } private int encodedSourceStart; private int encodedSourceEnd; private String sourceName; private int baseLineno = -1; private int endLineno = -1; private ObjArray functions; private ObjArray regexps; // a list of the formal parameters and local variables private ObjArray itsVariables

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> is relative only to the current * run of the CodeConsumer and will be normalized * later on by the SourceMap. * * @see SourceMap */ private static class Mapping { Node node; Position start; Position end; } /** * Starts the source mapping for the given * node at the current position. */ @Override void startSourceMapping(Node node) { if (createSrcMap && node.getProp(Node.SOURCEFILE_PROP) != null && node.getLineno() > 0) { int line = getCurrentLineIndex(); int index = getCurrentCharIndex(); // If the index is -1, we are not performing any mapping. if (index >= 0) { Mapping mapping = new Mapping(); mapping.node = node; mapping.start = new Position(line, index); mappings.push(mapping); allMappings.add(mapping); } } } /** * Finishes the source mapping for the given * node at the current position. */ @Override void endSourceMapping(Node node) { if (createSrcMap && node.getProp(Node.SOURCEFILE_PROP) != null && node.getLineno() > 0) { int line = getCurrentLineIndex(); int index = getCurrentCharIndex(); // If the index is -1, we are not performing any mapping. if (index >= 0) { Preconditions.checkState( !mappings.empty(), "Mismatch in start and end of mapping"); Mapping mapping = mappings.pop(); mapping.end = new Position(line, index); } } } /** * Generates the source map from the given code consumer, * appending the information it saved to the SourceMap * object given. */ @Override void generateSourceMap(SourceMap map){ if (createSrcMap) { for (Mapping mapping : allMappings) { map.addMapping(mapping.node, mapping.start, mapping.end); } } } /** * Reports to the code consumer that the given line has been cut at the * given position (i.e. a \n has been inserted there). All mappings in * the source maps after that position will be renormalized

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>Threshold; } public String getCode() { return code.toString(); } @Override char getLastChar() { return (code.length() > 0) ? code.charAt(code.length() - 1) : '\0'; } @Override int getCurrentBufferLength() { return code.length(); } @Override int getCurrentCharIndex() { return lineLength; } @Override int getCurrentLineIndex() { return lineIndex; } /** * Appends a string to the code, keeping track of the current line length. */ @Override void append(String str) { // For pretty printing: indent at the beginning of the line if (lineLength == 0) { for (int i = 0; i < indent; i++) { code.append(INDENT); lineLength += INDENT.length(); } } code.append(str); lineLength += str.length(); } /** * Adds a newline to the code, resetting the line length and handling * indenting for pretty printing. */ @Override void startNewLine() { if (lineLength > 0) { code.append('\n'); lineIndex++; lineLength = 0; } } @Override void maybeLineBreak() { maybeCutLine(); } /** * This may start a new line if the current line is longer than the line * length threshold. */ @Override void maybeCutLine() { if (lineLength > lineLengthThreshold) { startNewLine(); } } @Override void endLine() { startNewLine(); } @Override void appendBlockStart() { append(" {"); indent++; } @Override void appendBlockEnd() { endLine(); indent--; append("}"); } @Override void listSeparator() { add(", "); maybeLineBreak(); } @Override void endFunction(boolean statementContext) { super.endFunction(statementContext); if (statementContext) { startNewLine(); } } @Override void beginCaseBody() { super.beginCaseBody(); indent++; endLine(); } @Override void endCase

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> this.outputCharset = outCharset; return this; } /** * Whether the input AST guaranteed to be properly formed, fail if it isn't. */ Builder setValidation(boolean validation) { this.validation = validation; return this; } /** * Generates the source code and returns it. */ String build() { if (root == null) { throw new IllegalStateException( "Cannot build without root node being specified"); } Format outputFormat = outputTypes ? Format.TYPED : prettyPrint ? Format.PRETTY : Format.COMPACT; return toSource(root, outputFormat, lineBreak, lineLengthThreshold, sourceMap, outputCharset, validation); } } enum Format { COMPACT, PRETTY, TYPED } /** * Converts a tree to js code */ private static String toSource(Node root, Format outputFormat, boolean lineBreak, int lineLengthThreshold, SourceMap sourceMap, Charset outputCharset, boolean validation) { boolean createSourceMap = (sourceMap != null); CodeConsumer cp = outputFormat == Format.COMPACT ? new CompactCodePrinter( lineBreak, lineLengthThreshold, createSourceMap) : new PrettyCodePrinter(lineLengthThreshold, createSourceMap); CodeGenerator cg = outputFormat == Format.TYPED ? new TypedCodeGenerator(cp, outputCharset) : new CodeGenerator(cp, outputCharset, validation); cg.add(root); String code = ((HasGetCode) cp).getCode(); if (createSourceMap) { cp.generateSourceMap(sourceMap); } return code; } }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>AnnotationNames(); return annotationNames; } private static synchronized void initAnnotationNames() { if (annotationNames != null) { return; } Set<String> trimmedNames = Sets.newHashSet(); ResourceBundle config = ResourceBundle.getBundle(configResource); String[] names = config.getString("jsdoc.annotations").split(","); for (String name : names) { trimmedNames.add(name.trim()); } annotationNames = ImmutableSet.copyOf(trimmedNames); } /** * Parses the JavaScript text given by a reader. * * @param sourceName The filename. * @param sourceString Source code from the file. * @param errorReporter An error. * @param logger A logger. * @return The AST of the given text. * @throws IOException */ public static Node parse(String sourceName, String sourceString, Config config, ErrorReporter errorReporter, Logger logger) throws IOException { Context cx = Context.enter(); cx.setErrorReporter(errorReporter); cx.setLanguageVersion(Context.VERSION_1_5); CompilerEnvirons compilerEnv = new CompilerEnvirons(); compilerEnv.initFromContext(cx); compilerEnv.setRecordingComments(true); compilerEnv.setRecordingLocalJsDocComments(true); compilerEnv.setWarnTrailingComma(true); if (config.isIdeMode) { compilerEnv.setReservedKeywordAsIdentifier(true); compilerEnv.setAllowMemberExprAsFunctionName(true); } Parser p = new Parser(compilerEnv, errorReporter); AstRoot astRoot = null; try { astRoot = p.parse(sourceString, sourceName, 1); } catch (EvaluatorException e) { logger.info("Error parsing " + sourceName + ": " + e.getMessage()); } finally { Context.exit(); } Node root = null; if (astRoot != null) { root = IRFactory.transformTree( astRoot, sourceString, config, errorReporter); root.setIsSyntheticBlock(true); } return root; } }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> private void mismatch(NodeTraversal t, Node n, String msg, JSType found, JSTypeNative required) { mismatch(t, n, msg, found, getNativeType(required)); } private void mismatch(String sourceName, Node n, String msg, JSType found, JSType required) { registerMismatch(found, required); compiler.report( JSError.make(sourceName, n, TYPE_MISMATCH_WARNING, formatFoundRequired(msg, found, required))); } private void registerMismatch(JSType found, JSType required) { // Don't register a mismatch for differences in null or undefined or if the // code didn't downcast. found = found.restrictByNotNullOrUndefined(); required = required.restrictByNotNullOrUndefined(); if (found.canAssignTo(required) || required.canAssignTo(found)) { return; } mismatches.add(new TypeMismatch(found, required)); if (found instanceof FunctionType && required instanceof FunctionType) { FunctionType fnTypeA = ((FunctionType) found); FunctionType fnTypeB = ((FunctionType) required); Iterator<Node> paramItA = fnTypeA.getParameters().iterator(); Iterator<Node> paramItB = fnTypeB.getParameters().iterator(); while (paramItA.hasNext() && paramItB.hasNext()) { registerIfMismatch(paramItA.next().getJSType(), paramItB.next().getJSType()); } registerIfMismatch(fnTypeA.getReturnType(), fnTypeB.getReturnType()); } } private void registerIfMismatch(JSType found, JSType required) { if (found != null && required != null && !found.canAssignTo(required)) { registerMismatch(found, required); } } /** * Formats a found/required error message. */ private String formatFoundRequired(String description, JSType found, JSType required) { return MessageFormat.format(FOUND_REQUIRED, description, found, required); } /** * Given a node, get a human-readable name for the type of that node so * that will be easy for the programmer to find the original declaration. * * For example, if SubFoo's property "

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> + "var x = a;" }); } public void testVarMovement7() { // Don't move a variable higher in the dependency tree testSame(createModuleStar( // m1 "function f() {g();}", // m2 "function g(){};")); } public void testClone1() { test(createModuleChain( // m1 "function f(){} f.prototype.clone = function() { return new f };", // m2 "var a = (new f).clone();"), new String[] { // m1 "", "function f(){} f.prototype.clone = function() { return new f() };" + // m2 "var a = (new f).clone();" }); } public void testClone2() { test(createModuleChain( // m1 "function f(){}" + "f.prototype.cloneFun = function() {" + " return function() {new f}" + "};", // m2 "var a = (new f).cloneFun();"), new String[] { // m1 "", "function f(){}" + "f.prototype.cloneFun = function() {" + " return function() {new f}" + "};" + // m2 "var a = (new f).cloneFun();" }); } public void testEmptyModule() { // When the dest module is empty, it might try to move the code to the // one of the modules that the empty module depends on. In some cases // this might ended up to be the same module as the definition of the code. // When that happens, CrossMooduleCodeMotion might report a code change // while nothing is moved. This should not be a problem if we know all // modules are non-empty. JSModule m1 = new JSModule("m1"); m1.add(JSSourceFile.fromCode("m1", "function x() {}")); JSModule empty = new JSModule("empty"); empty.addDependency(m1); JSModule m2 = new JSModule("m2"); m2.add(JSSourceFile.fromCode("m2", "x()")); m2.addDependency

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>(empty); JSModule m3 = new JSModule("m3"); m3.add(JSSourceFile.fromCode("m3", "x()")); m3.addDependency(empty); test(new JSModule[] {m1,empty,m2,m3}, new String[] { "", "function x() {}", "x()", "x()" }); } }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> = def.getValue(); Node inputValue = dominantReplacements.get(defineName); Node finalValue = inputValue != null ? inputValue : info.getLastValue(); if (finalValue != info.initialValue) { info.initialValueParent.replaceChild( info.initialValue, finalValue.cloneTree()); compiler.addToDebugLog("Overriding @define variable " + defineName); changed = changed || finalValue.getType() != info.initialValue.getType() || !finalValue.isEquivalentTo(info.initialValue); } } if (changed) { compiler.reportCodeChange(); } Set<String> unusedReplacements = dominantReplacements.keySet(); unusedReplacements.removeAll(allDefines.keySet()); unusedReplacements.removeAll(KNOWN_DEFINES); for (String unknownDefine : unusedReplacements) { compiler.report(JSError.make(UNKNOWN_DEFINE_WARNING, unknownDefine)); } } private static String format(MessageFormat format, Object... params) { return format.format(params); } /** * Finds all defines, and creates a {@link DefineInfo} data structure for * each one. * @return A map of {@link DefineInfo} structures, keyed by name. */ private Map<String, DefineInfo> collectDefines(Node root, GlobalNamespace namespace) { // Find all the global names with a @define annotation List<Name> allDefines = Lists.newArrayList(); for (Name name : namespace.getNameIndex().values()) { if (name.docInfo != null && name.docInfo.isDefine()) { allDefines.add(name); } else if (name.refs != null) { for (Ref ref : name.refs) { Node n = ref.node; Node parent = ref.node.getParent(); JSDocInfo info = n.getJSDocInfo(); if (info == null && parent.getType() == Token.VAR && parent.hasOneChild()) { info = parent.getJSDocInfo(); } if (info != null && info.isDefine()) { allDefines.add(name); break; } } } } CollectDefines pass = new CollectDefines(compiler, all

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> ObjToIntMap implements Serializable { static final long serialVersionUID = -1542220580748809402L; // Map implementation via hashtable, // follows "The Art of Computer Programming" by Donald E. Knuth // ObjToIntMap is a copy cat of ObjToIntMap with API adjusted to object keys public static class Iterator { Iterator(ObjToIntMap master) { this.master = master; } final void init(Object[] keys, int[] values, int keyCount) { this.keys = keys; this.values = values; this.cursor = -1; this.remaining = keyCount; } public void start() { master.initIterator(this); next(); } public boolean done() { return remaining < 0; } public void next() { if (remaining == -1) Kit.codeBug(); if (remaining == 0) { remaining = -1; cursor = -1; }else { for (++cursor; ; ++cursor) { Object key = keys[cursor]; if (key != null && key != DELETED) { --remaining; break; } } } } public Object getKey() { Object key = keys[cursor]; if (key == UniqueTag.NULL_VALUE) { key = null; } return key; } public int getValue() { return values[cursor]; } public void setValue(int value) { values[cursor] = value; } ObjToIntMap master; private int cursor; private int remaining; private Object[] keys; private int[] values; } public ObjToIntMap() { this(4); } public ObjToIntMap(int keyCountHint) { if (keyCountHint < 0) Kit.codeBug(); // Table grow when number of stored keys >= 3/4 of max capacity int minimalCapacity = keyCountHint * 4 / 3; int i; for (i = 2; (1 << i) < minimalCapacity; ++i) { } power = i; if (check && power < 2) Kit.codeBug(); } public boolean isEmpty() { return key

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>Count == 0; } public int size() { return keyCount; } public boolean has(Object key) { if (key == null) { key = UniqueTag.NULL_VALUE; } return 0 <= findIndex(key); } /** * Get integer value assigned with key. * @return key integer value or defaultValue if key is absent */ public int get(Object key, int defaultValue) { if (key == null) { key = UniqueTag.NULL_VALUE; } int index = findIndex(key); if (0 <= index) { return values[index]; } return defaultValue; } /** * Get integer value assigned with key. * @return key integer value * @throws RuntimeException if key does not exist */ public int getExisting(Object key) { if (key == null) { key = UniqueTag.NULL_VALUE; } int index = findIndex(key); if (0 <= index) { return values[index]; } // Key must exist Kit.codeBug(); return 0; } public void put(Object key, int value) { if (key == null) { key = UniqueTag.NULL_VALUE; } int index = ensureIndex(key); values[index] = value; } /** * If table already contains a key that equals to keyArg, return that key * while setting its value to zero, otherwise add keyArg with 0 value to * the table and return it. */ public Object intern(Object keyArg) { boolean nullKey = false; if (keyArg == null) { nullKey = true; keyArg = UniqueTag.NULL_VALUE; } int index = ensureIndex(keyArg); values[index] = 0; return (nullKey) ? null : keys[index]; } public void remove(Object key) { if (key == null) { key = UniqueTag.NULL_VALUE; } int index = findIndex(key); if (0 <= index) { keys[index] = DELETED; --keyCount; } } public void clear() { int i = keys.length; while (i != 0) { keys

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>[--i] = null; } keyCount = 0; occupiedCount = 0; } public Iterator newIterator() { return new Iterator(this); } // The sole purpose of the method is to avoid accessing private fields // from the Iterator inner class to workaround JDK 1.1 compiler bug which // generates code triggering VerifierError on recent JVMs final void initIterator(Iterator i) { i.init(keys, values, keyCount); } /** Return array of present keys */ public Object[] getKeys() { Object[] array = new Object[keyCount]; getKeys(array, 0); return array; } public void getKeys(Object[] array, int offset) { int count = keyCount; for (int i = 0; count != 0; ++i) { Object key = keys[i]; if (key != null && key != DELETED) { if (key == UniqueTag.NULL_VALUE) { key = null; } array[offset] = key; ++offset; --count; } } } private static int tableLookupStep(int fraction, int mask, int power) { int shift = 32 - 2 * power; if (shift >= 0) { return ((fraction >>> shift) & mask) | 1; } else { return (fraction & (mask >>> -shift)) | 1; } } private int findIndex(Object key) { if (keys != null) { int hash = key.hashCode(); int fraction = hash * A; int index = fraction >>> (32 - power); Object test = keys[index]; if (test != null) { int N = 1 << power; if (test == key || (values[N + index] == hash && test.equals(key))) { return index; } // Search in table after first failed attempt int mask = N - 1; int step = tableLookupStep(fraction, mask, power); int n = 0; for (;;) { if (check) { if (n >= occupiedCount) Kit.codeBug(); ++n; } index = (index + step) & mask

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>; test = keys[index]; if (test == null) { break; } if (test == key || (values[N + index] == hash && test.equals(key))) { return index; } } } } return -1; } // Insert key that is not present to table without deleted entries // and enough free space private int insertNewKey(Object key, int hash) { if (check && occupiedCount != keyCount) Kit.codeBug(); if (check && keyCount == 1 << power) Kit.codeBug(); int fraction = hash * A; int index = fraction >>> (32 - power); int N = 1 << power; if (keys[index] != null) { int mask = N - 1; int step = tableLookupStep(fraction, mask, power); int firstIndex = index; do { if (check && keys[index] == DELETED) Kit.codeBug(); index = (index + step) & mask; if (check && firstIndex == index) Kit.codeBug(); } while (keys[index] != null); } keys[index] = key; values[N + index] = hash; ++occupiedCount; ++keyCount; return index; } private void rehashTable() { if (keys == null) { if (check && keyCount != 0) Kit.codeBug(); if (check && occupiedCount != 0) Kit.codeBug(); int N = 1 << power; keys = new Object[N]; values = new int[2 * N]; } else { // Check if removing deleted entries would free enough space if (keyCount * 2 >= occupiedCount) { // Need to grow: less then half of deleted entries ++power; } int N = 1 << power; Object[] oldKeys = keys; int[] oldValues = values; int oldN = oldKeys.length; keys = new Object[N]; values = new int[2 * N]; int remaining = keyCount; occupiedCount = keyCount = 0; for (int i = 0; remaining != 0; ++i) {

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> Object key = oldKeys[i]; if (key != null && key != DELETED) { int keyHash = oldValues[oldN + i]; int index = insertNewKey(key, keyHash); values[index] = oldValues[i]; --remaining; } } } } // Ensure key index creating one if necessary private int ensureIndex(Object key) { int hash = key.hashCode(); int index = -1; int firstDeleted = -1; if (keys != null) { int fraction = hash * A; index = fraction >>> (32 - power); Object test = keys[index]; if (test != null) { int N = 1 << power; if (test == key || (values[N + index] == hash && test.equals(key))) { return index; } if (test == DELETED) { firstDeleted = index; } // Search in table after first failed attempt int mask = N - 1; int step = tableLookupStep(fraction, mask, power); int n = 0; for (;;) { if (check) { if (n >= occupiedCount) Kit.codeBug(); ++n; } index = (index + step) & mask; test = keys[index]; if (test == null) { break; } if (test == key || (values[N + index] == hash && test.equals(key))) { return index; } if (test == DELETED && firstDeleted < 0) { firstDeleted = index; } } } } // Inserting of new key if (check && keys != null && keys[index] != null) Kit.codeBug(); if (firstDeleted >= 0) { index = firstDeleted; } else { // Need to consume empty entry: check occupation level if (keys == null || occupiedCount * 4 >= (1 << power) * 3) { // Too litle unused entries: rehash rehashTable(); return insertNewKey(key, hash); } ++occupiedCount; } keys[index] = key; values[(1 << power) +

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> index] = hash; ++keyCount; return index; } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); int count = keyCount; for (int i = 0; count != 0; ++i) { Object key = keys[i]; if (key != null && key != DELETED) { --count; out.writeObject(key); out.writeInt(values[i]); } } } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); int writtenKeyCount = keyCount; if (writtenKeyCount != 0) { keyCount = 0; int N = 1 << power; keys = new Object[N]; values = new int[2 * N]; for (int i = 0; i != writtenKeyCount; ++i) { Object key = in.readObject(); int hash = key.hashCode(); int index = insertNewKey(key, hash); values[index] = in.readInt(); } } } // A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32) // See Knuth etc. private static final int A = 0x9e3779b9; private static final Object DELETED = new Object(); // Structure of kyes and values arrays (N == 1 << power): // keys[0 <= i < N]: key value or null or DELETED mark // values[0 <= i < N]: value of key at keys[i] // values[N <= i < 2*N]: hash code of key at keys[i-N] private transient Object[] keys; private transient int[] values; private int power; private int keyCount; private transient int occupiedCount; // == keyCount + deleted_count // If true, enables consitency checks private static final boolean check = false; /* TEST START public static void main(String[] args) { if (!check) { System.err.println("Set check to true and re-run"); throw new RuntimeException("Set check

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.collect.Lists; import com.google.javascript.jscomp.CheckLevel; import java.util.*; /** * WarningsGuard that represents just a chain of other guards. For example we * could have following chain * 1) all warnings outside of /foo/ should be suppressed * 2) errors with key JSC_BAR should be marked as warning * 3) the rest should be reported as error * * This class is designed for such behaviour. * * */ public class ComposeWarningsGuard extends WarningsGuard { private final List<WarningsGuard> guards; private static final Comparator<WarningsGuard> guardComparator = new Comparator<WarningsGuard>() { @Override public int compare(WarningsGuard a, WarningsGuard b) { return a.getPriority() - b.getPriority(); } }; public ComposeWarningsGuard(List<WarningsGuard> guards) { this.guards = Lists.newArrayList(); addGuards(guards); } public ComposeWarningsGuard(WarningsGuard... guards) { this(Lists.newArrayList(guards)); } void addGuard(WarningsGuard guard) { if (guard instanceof ComposeWarningsGuard) { addGuards(((ComposeWarningsGuard) guard).guards); } else { int index = Collections.binarySearch(this.guards, guard, guardComparator); if (index < 0) { index = -index - 1; } this.guards.add(index, guard); } }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> pass being tested. */ private boolean normalizeEnabled = false; /** Whether the expected js strings should be normalized. */ private boolean normalizeExpected = false; /** Whether to check that all line number information is preserved. */ private boolean checkLineNumbers = false; /** * An expected symbol table error. Only useful for testing the * symbol table error-handling. */ private DiagnosticType expectedSymbolTableError = null; /** * Whether the MarkNoSideEffectsCalls pass runs before the pass being tested */ private boolean markNoSideEffects = false; /** The most recently used Compiler instance. */ private Compiler lastCompiler; /** * Constructs a test. * * @param externs Externs JS as a string * @param compareAsTree True to compare output & expected as a node tree. * 99% of the time you want to compare as a tree. There are a few * special cases where you don't, like if you want to test the code * printing of "unnatural" syntax trees. For example, * * <pre> * IF * IF * STATEMENT * ELSE * STATEMENT * </pre> */ protected CompilerTestCase(String externs, boolean compareAsTree) { this.externsInputs = new JSSourceFile[] { JSSourceFile.fromCode("externs", externs) }; this.compareAsTree = compareAsTree; this.parseTypeInfo = false; } /** * Constructs a test. Uses AST comparison. * @param externs Externs JS as a string */ protected CompilerTestCase(String externs) { this(externs, true); } /** * Constructs a test. Uses AST comparison and no externs. */ protected CompilerTestCase() { this("", true); } /** * Gets the compiler pass instance to use for a test. * * @param compiler The compiler * @return The pass to test */ protected abstract CompilerPass getProcessor(Compiler compiler); /** * Gets the compiler options to use for this test. Defaults to do nothing * options. * * This is really only for configuring warnings guards. Use getProcessor * to determine what passes should be run. */

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> is expected * @param warning Expected warning, or null if no warning is expected */ public void test(String js, String expected, DiagnosticType error, DiagnosticType warning) { test(externsInputs, js, expected, error, warning, null); } /** * Verifies that the compiler pass's JS output matches the expected output * and (optionally) that an expected warning is issued. Or, if an error is * expected, this method just verifies that the error is encountered. * * @param externs Externs input * @param js Input * @param expected Expected output, or null if an error is expected * @param error Expected error, or null if no error is expected * @param warning Expected warning, or null if no warning is expected */ public void test(String externs, String js, String expected, DiagnosticType error, DiagnosticType warning) { test(externs, js, expected, error, warning, null); } /** * Verifies that the compiler pass's JS output matches the expected output * and (optionally) that an expected warning is issued. Or, if an error is * expected, this method just verifies that the error is encountered. * * @param externs Externs input * @param js Input * @param expected Expected output, or null if an error is expected * @param error Expected error, or null if no error is expected * @param warning Expected warning, or null if no warning is expected * @param description The description of the expected warning, * or null if no warning is expected or if the warning's description * should not be examined */ public void test(String externs, String js, String expected, DiagnosticType error, DiagnosticType warning, String description) { JSSourceFile[] externsInputs = new JSSourceFile[]{ JSSourceFile.fromCode("externs", externs) }; test(externsInputs, js, expected, error, warning, description); } /** * Verifies that the compiler pass's JS output matches the expected output * and (optionally) that an expected warning is issued. Or, if an error is * expected, this method just verifies that the error is encountered. * * @param externs Extern

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>s inputs * @param js Input * @param expected Expected output, or null if an error is expected * @param error Expected error, or null if no error is expected * @param warning Expected warning, or null if no warning is expected * @param description The description of the expected warning, * or null if no warning is expected or if the warning's description * should not be examined */ public void test(JSSourceFile[] externs, String js, String expected, DiagnosticType error, DiagnosticType warning, String description) { Compiler compiler = createCompiler(); lastCompiler = compiler; BaseJSTypeTestCase.addNativeProperties(compiler.getTypeRegistry()); CompilerOptions options = getOptions(); // Note that in this context, turning on the checkTypes option won't // actually cause the type check to run. options.checkTypes = parseTypeInfo; compiler.init(externs, new JSSourceFile[] { JSSourceFile.fromCode("testcode", js) }, options); test(compiler, new String[] { expected }, error, warning, description); } /** * Verifies that the compiler pass's JS output matches the expected output. * * @param js Inputs * @param expected Expected JS output */ public void test(String[] js, String[] expected) { test(js, expected, null); } /** * Verifies that the compiler pass's JS output matches the expected output, * or that an expected error is encountered. * * @param js Inputs * @param expected Expected JS output * @param error Expected error, or null if no error is expected */ public void test(String[] js, String[] expected, DiagnosticType error) { test(js, expected, error, null); } /** * Verifies that the compiler pass's JS output matches the expected output * and (optionally) that an expected warning is issued. Or, if an error is * expected, this method just verifies that the error is encountered. * * @param js Inputs * @param expected Expected JS output * @param error Expected error, or null if no error is expected * @param warning Expected warning, or null if no warning is expected */ public void test(String[] js, String[] expected, Diagnostic

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>Type error, DiagnosticType warning) { test(js, expected, error, warning, null); } /** * Verifies that the compiler pass's JS output matches the expected output * and (optionally) that an expected warning is issued. Or, if an error is * expected, this method just verifies that the error is encountered. * * @param js Inputs * @param expected Expected JS output * @param error Expected error, or null if no error is expected * @param warning Expected warning, or null if no warning is expected * @param description The description of the expected warning, * or null if no warning is expected or if the warning's description * should not be examined */ public void test(String[] js, String[] expected, DiagnosticType error, DiagnosticType warning, String description) { Compiler compiler = createCompiler(); lastCompiler = compiler; JSSourceFile[] inputs = new JSSourceFile[js.length]; for (int i = 0; i < js.length; i++) { inputs[i] = JSSourceFile.fromCode("input" + i, js[i]); } compiler.init(externsInputs, inputs, getOptions()); test(compiler, expected, error, warning, description); } /** * Verifies that the compiler pass's JS output matches the expected output. * * @param modules Module inputs * @param expected Expected JS outputs (one per module) */ public void test(JSModule[] modules, String[] expected) { test(modules, expected, null); } /** * Verifies that the compiler pass's JS output matches the expected output, * or that an expected error is encountered. * * @param modules Module inputs * @param expected Expected JS outputs (one per module) * @param error Expected error, or null if no error is expected */ public void test(JSModule[] modules, String[] expected, DiagnosticType error) { test(modules, expected, error, null); } /** * Verifies that the compiler pass's JS output matches the expected output * and (optionally) that an expected warning is issued. Or, if an error is * expected, this method just verifies that the error is encountered. * * @param

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> description is issued. * * @param externs Externs input * @param js Input and output * @param warning Expected warning, or null if no warning is expected * @param description The description of the expected warning, * or null if no warning is expected or if the warning's description * should not be examined */ public void testSame(String externs, String js, DiagnosticType warning, String description) { JSSourceFile[] externsInputs = new JSSourceFile[]{ JSSourceFile.fromCode("externs", externs) }; test(externsInputs, js, js, null, warning, description); } /** * Verifies that the compiler pass's JS output is the same as its input. * * @param js Inputs and outputs */ public void testSame(String[] js) { test(js, js); } /** * Verifies that the compiler pass's JS output is the same as its input, * and emits the given error. * * @param js Inputs and outputs * @param error Expected error, or null if no error is expected */ public void testSame(String[] js, DiagnosticType error) { test(js, js, error); } /** * Verifies that the compiler pass's JS output is the same as its input, * and emits the given error and warning. * * @param js Inputs and outputs * @param error Expected error, or null if no error is expected * @param warning Expected warning, or null if no warning is expected */ public void testSame(String[] js, DiagnosticType error, DiagnosticType warning) { test(js, js, error, warning); } /** * Verifies that the compiler pass's JS output is the same as the input. * * @param modules Module inputs */ public void testSame(JSModule[] modules) { testSame(modules, null); } /** * Verifies that the compiler pass's JS output is the same as the input. * * @param modules Module inputs * @param warning A warning, or null for no expected warning. */ public void testSame(JSModule[] modules, DiagnosticType warning) { try { String[] expected = new String[

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>modules.length]; for (int i = 0; i < modules.length; i++) { expected[i] = ""; for (CompilerInput input : modules[i].getInputs()) { expected[i] += input.getSourceFile().getCode(); } } test(modules, expected, null, warning); } catch (IOException e) { throw new RuntimeException(e); } } /** * Verifies that the compiler pass's JS output matches the expected output * and (optionally) that an expected warning is issued. Or, if an error is * expected, this method just verifies that the error is encountered. * * @param compiler A compiler that has been initialized via * {@link Compiler#init} * @param expected Expected output, or null if an error is expected * @param error Expected error, or null if no error is expected * @param warning Expected warning, or null if no warning is expected */ protected void test(Compiler compiler, String[] expected, DiagnosticType error, DiagnosticType warning) { test(compiler, expected, error, warning, null); } /** * Verifies that the compiler pass's JS output matches the expected output * and (optionally) that an expected warning is issued. Or, if an error is * expected, this method just verifies that the error is encountered. * * @param compiler A compiler that has been initialized via * {@link Compiler#init} * @param expected Expected output, or null if an error is expected * @param error Expected error, or null if no error is expected * @param warning Expected warning, or null if no warning is expected * @param description The description of the expected warning, * or null if no warning is expected or if the warning's description * should not be examined */ private void test(Compiler compiler, String[] expected, DiagnosticType error, DiagnosticType warning, String description) { RecentChange recentChange = new RecentChange(); compiler.addChangeHandler(recentChange); Node root = compiler.parseInputs(); assertTrue("Unexpected parse error(s): " + Joiner.on("\n").join(compiler.getErrors()), root != null); Node externsRoot = root.getFirstChild(); Node mainRoot = root.getLastChild

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>(); // Save the tree for later comparison. Node rootClone = root.cloneTree(); Node externsRootClone = rootClone.getFirstChild(); Node mainRootClone = rootClone.getLastChild(); int numRepetitions = getNumRepetitions(); ErrorManager[] errorManagers = new ErrorManager[numRepetitions]; int aggregateWarningCount = 0; List<JSError> aggregateWarnings = Lists.newArrayList(); boolean hasCodeChanged = false; assertFalse("Code should not change before processing", recentChange.hasCodeChanged()); for (int i = 0; i < numRepetitions; ++i) { if (compiler.getErrorCount() == 0) { errorManagers[i] = new BlackHoleErrorManager(compiler); // Only run the type checking pass once, if asked. // Running it twice can cause unpredictable behavior because duplicate // objects for the same type are created, and the type system // uses reference equality to compare many types. if (typeCheckEnabled && i == 0) { TypeCheck check = createTypeCheck(compiler, typeCheckLevel); check.processForTesting(externsRoot, mainRoot); } // Only run the normalize pass once, if asked. if (normalizeEnabled && i == 0) { Normalize normalize = new Normalize(compiler, false); normalize.process(externsRoot, mainRoot); compiler.setNormalized(); } if (markNoSideEffects && i == 0) { MarkNoSideEffectCalls mark = new MarkNoSideEffectCalls(compiler); mark.process(externsRoot, mainRoot); } recentChange.reset(); getProcessor(compiler).process(externsRoot, mainRoot); if (checkLineNumbers) { (new LineNumberCheck(compiler)).process(externsRoot, mainRoot); } hasCodeChanged = hasCodeChanged || recentChange.hasCodeChanged(); aggregateWarningCount += errorManagers[i].getWarningCount(); aggregateWarnings.addAll(Lists.newArrayList(compiler.getWarnings())); if (normalizeEnabled) { boolean verifyDeclaredConstants = true; new Normalize.VerifyConstants(compiler, verifyDeclaredConstants) .process(externsRoot, mainRoot); } } } if (error == null) {

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> assertEquals( "Unexpected error(s): " + Joiner.on("\n").join(compiler.getErrors()), 0, compiler.getErrorCount()); // Verify the symbol table. ErrorManager symbolTableErrorManager = new BlackHoleErrorManager(compiler); Node expectedRoot = parseExpectedJs(expected); expectedRoot.detachFromParent(); SymbolTable table = compiler.acquireSymbolTable(); table.verify( new Node(Token.BLOCK, externsRoot.cloneTree(), expectedRoot), mainRoot.getParent()); table.release(); JSError[] stErrors = symbolTableErrorManager.getErrors(); if (expectedSymbolTableError != null) { assertEquals("There should be one error.", 1, stErrors.length); assertEquals(expectedSymbolTableError, stErrors[0].getType()); } else { assertEquals("Unexpected symbol table error(s): " + Joiner.on("\n").join(stErrors), 0, stErrors.length); } if (warning == null) { assertEquals( "Unexpected warning(s): " + Joiner.on("\n").join(aggregateWarnings), 0, aggregateWarningCount); } else { assertEquals("There should be one warning, repeated " + numRepetitions + " time(s).", numRepetitions, aggregateWarningCount); for (int i = 0; i < numRepetitions; ++i) { JSError[] warnings = errorManagers[i].getWarnings(); JSError actual = warnings[0]; assertEquals(warning, actual.getType()); // Make sure that source information is always provided. if (!allowSourcelessWarnings) { assertTrue("Missing source file name in warning", actual.sourceName != null && !actual.sourceName.isEmpty()); assertTrue("Missing line number in warning", -1 != actual.lineNumber); assertTrue("Missing char number in warning", -1 != actual.getCharno()); } if (description != null) { assertEquals(description, actual.description); } } } if (normalizeEnabled) { Normalize normalize = new Normalize(compiler, false); normalize.process(externsRootClone, mainRootClone); } if (mainRootClone.checkTreeEqualsSilent(mainRoot)) { assertFalse(

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> + errors, 1, compiler.getErrorCount()); assertEquals(errors, error, compiler.getErrors()[0].getType()); } } /** * Parses expected js inputs and returns the root of the parse tree. */ private Node parseExpectedJs(String[] expected) { Compiler compiler = createCompiler(); JSSourceFile[] inputs = new JSSourceFile[expected.length]; for (int i = 0; i < expected.length; i++) { inputs[i] = JSSourceFile.fromCode("expected" + i, expected[i]); } compiler.init(externsInputs, inputs, getOptions()); Node root = compiler.parseInputs(); assertTrue("Unexpected parse error(s): " + Joiner.on("\n").join(compiler.getErrors()), root != null); Node externsRoot = root.getFirstChild(); Node mainRoot = externsRoot.getNext(); // Only run the normalize pass, if asked. if (normalizeEnabled && normalizeExpected && !compiler.hasErrors()) { Normalize normalize = new Normalize(compiler, false); normalize.process(externsRoot, mainRoot); compiler.setNormalized(); } return mainRoot; } Node parseExpectedJs(String expected) { return parseExpectedJs(new String[] {expected}); } /** * Generates a list of modules from a list of inputs, such that each module * depends on the module before it. */ static JSModule[] createModuleChain(String... inputs) { JSModule[] modules = createModules(inputs); for (int i = 1; i < modules.length; i++) { modules[i].addDependency(modules[i - 1]); } return modules; } /** * Generates a list of modules from a list of inputs, such that each module * depends on the first module. */ static JSModule[] createModuleStar(String... inputs) { JSModule[] modules = createModules(inputs); for (int i = 1; i < modules.length; i++) { modules[i].addDependency(modules[0]); } return modules; } /** * Generates a list of modules from a list of inputs. Does not generate any * dependencies between the modules.

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> */ static JSModule[] createModules(String... inputs) { JSModule[] modules = new JSModule[inputs.length]; for (int i = 0; i < inputs.length; i++) { JSModule module = modules[i] = new JSModule("m" + i); module.add(JSSourceFile.fromCode("i" + i, inputs[i])); } return modules; } private static class BlackHoleErrorManager extends BasicErrorManager { private BlackHoleErrorManager(Compiler compiler) { compiler.setErrorManager(this); } @Override public void println(CheckLevel level, JSError error) {} @Override public void printSummary() {} } private Compiler createCompiler() { Compiler compiler = new Compiler(); return compiler; } protected void setExpectedSymbolTableError(DiagnosticType type) { this.expectedSymbolTableError = type; } }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>/* * Copyright 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.collect.Sets; import com.google.javascript.jscomp.CheckLevel; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.SortedSet; /** * <p>A basic error manager that sorts all errors and warnings reported to it to * generate a sorted report when the {@link #generateReport()} method * is called.</p> * * <p>This error manager does not produce any output, but subclasses can * override the {@link #println(CheckLevel, JSError)} method to generate custom * output.</p> * * * */ public abstract class BasicErrorManager implements ErrorManager { private final SortedSet<ErrorWithLevel> messages = Sets.newTreeSet(new LeveledJSErrorComparator()); private int errorCount = 0; private int warningCount = 0; private double typedPercent = 0.0; public void report(CheckLevel level, JSError error) { if (messages.add(new ErrorWithLevel(error, level))) { if (level == CheckLevel.ERROR) { errorCount++; } else if (level == CheckLevel.WARNING) { warningCount++; } } } public void generateReport() { for (ErrorWithLevel message : messages) { println(message.level, message.error); } printSummary(); } /** * Print a message with a trailing new line. This method is called by the * {@link #generate

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>Report()} method when generating messages. */ public abstract void println(CheckLevel level, JSError error); /** * Print the summary of the compilation - number of errors and warnings. */ protected abstract void printSummary(); public int getErrorCount() { return errorCount; } public int getWarningCount() { return warningCount; } public JSError[] getErrors() { return toArray(CheckLevel.ERROR); } public JSError[] getWarnings() { return toArray(CheckLevel.WARNING); } public void setTypedPercent(double typedPercent) { this.typedPercent = typedPercent; } public double getTypedPercent() { return typedPercent; } private JSError[] toArray(CheckLevel level) { List<JSError> errors = new ArrayList<JSError>(messages.size()); for (ErrorWithLevel p : messages) { if (p.level == level) { errors.add(p.error); } } return errors.toArray(new JSError[errors.size()]); } /** * <p>Comparator of {@link JSError} with an associated {@link CheckLevel}. * The ordering is the standard lexical ordering on the quintuple * (file name, line number, {@link CheckLevel}, * character number, description).</p> * * <p>Note: this comparator imposes orderings that are inconsistent with * {@link JSError#equals(Object)}.</p> */ static final class LeveledJSErrorComparator implements Comparator<ErrorWithLevel> { private static final int P1_LT_P2 = -1; private static final int P1_GT_P2 = 1; public int compare(ErrorWithLevel p1, ErrorWithLevel p2) { // null is the smallest value if (p2 == null) { if (p1 == null) { return 0; } else { return P1_GT_P2; } } // check level if (p1.level != p2.level) { return p2.level.compareTo(p1.level); } // sourceName comparison String source1 = p1.error.sourceName; String source2

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>658296L; public ObjArray() { } public final boolean isSealed() { return sealed; } public final void seal() { sealed = true; } public final boolean isEmpty() { return size == 0; } public final int size() { return size; } public final void setSize(int newSize) { if (newSize < 0) throw new IllegalArgumentException(); if (sealed) throw onSeledMutation(); int N = size; if (newSize < N) { for (int i = newSize; i != N; ++i) { setImpl(i, null); } } else if (newSize > N) { if (newSize > FIELDS_STORE_SIZE) { ensureCapacity(newSize); } } size = newSize; } public final Object get(int index) { if (!(0 <= index && index < size)) throw onInvalidIndex(index, size); return getImpl(index); } public final void set(int index, Object value) { if (!(0 <= index && index < size)) throw onInvalidIndex(index, size); if (sealed) throw onSeledMutation(); setImpl(index, value); } @SuppressWarnings("fallthrough") private Object getImpl(int index) { switch (index) { case 0: return f0; case 1: return f1; case 2: return f2; case 3: return f3; case 4: return f4; } return data[index - FIELDS_STORE_SIZE]; } @SuppressWarnings("fallthrough") private void setImpl(int index, Object value) { switch (index) { case 0: f0 = value; break; case 1: f1 = value; break; case 2: f2 = value; break; case 3: f3 = value; break; case 4: f4 = value; break; default: data[index - FIELDS_STORE_SIZE] = value; } } public int indexOf(Object obj) { int N = size; for (

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>int i = 0; i != N; ++i) { Object current = getImpl(i); if (current == obj || (current != null && current.equals(obj))) { return i; } } return -1; } public int lastIndexOf(Object obj) { for (int i = size; i != 0;) { --i; Object current = getImpl(i); if (current == obj || (current != null && current.equals(obj))) { return i; } } return -1; } public final Object peek() { int N = size; if (N == 0) throw onEmptyStackTopRead(); return getImpl(N - 1); } @SuppressWarnings("fallthrough") public final Object pop() { if (sealed) throw onSeledMutation(); int N = size; --N; Object top; switch (N) { case -1: throw onEmptyStackTopRead(); case 0: top = f0; f0 = null; break; case 1: top = f1; f1 = null; break; case 2: top = f2; f2 = null; break; case 3: top = f3; f3 = null; break; case 4: top = f4; f4 = null; break; default: top = data[N - FIELDS_STORE_SIZE]; data[N - FIELDS_STORE_SIZE] = null; } size = N; return top; } public final void push(Object value) { add(value); } public final void add(Object value) { if (sealed) throw onSeledMutation(); int N = size; if (N >= FIELDS_STORE_SIZE) { ensureCapacity(N + 1); } size = N + 1; setImpl(N, value); } @SuppressWarnings("fallthrough") public final void add(int index, Object value) { int N = size; if (!(0 <= index && index <= N)) throw onInvalidIndex(index, N + 1); if (sealed) throw onSeledMutation(); Object

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> default: if (index != N) { System.arraycopy(data, index - FIELDS_STORE_SIZE + 1, data, index - FIELDS_STORE_SIZE, N - index); } data[N - FIELDS_STORE_SIZE] = null; } size = N; } public final void clear() { if (sealed) throw onSeledMutation(); int N = size; for (int i = 0; i != N; ++i) { setImpl(i, null); } size = 0; } public final Object[] toArray() { Object[] array = new Object[size]; toArray(array, 0); return array; } public final void toArray(Object[] array) { toArray(array, 0); } @SuppressWarnings("fallthrough") public final void toArray(Object[] array, int offset) { int N = size; switch (N) { default: System.arraycopy(data, 0, array, offset + FIELDS_STORE_SIZE, N - FIELDS_STORE_SIZE); case 5: array[offset + 4] = f4; case 4: array[offset + 3] = f3; case 3: array[offset + 2] = f2; case 2: array[offset + 1] = f1; case 1: array[offset + 0] = f0; case 0: break; } } private void ensureCapacity(int minimalCapacity) { int required = minimalCapacity - FIELDS_STORE_SIZE; if (required <= 0) throw new IllegalArgumentException(); if (data == null) { int alloc = FIELDS_STORE_SIZE * 2; if (alloc < required) { alloc = required; } data = new Object[alloc]; } else { int alloc = data.length; if (alloc < required) { if (alloc <= FIELDS_STORE_SIZE) { alloc = FIELDS_STORE_SIZE * 2; } else { alloc *= 2; } if (alloc < required) { alloc = required; }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> Object[] tmp = new Object[alloc]; if (size > FIELDS_STORE_SIZE) { System.arraycopy(data, 0, tmp, 0, size - FIELDS_STORE_SIZE); } data = tmp; } } } private static RuntimeException onInvalidIndex(int index, int upperBound) { // \u2209 is "NOT ELEMENT OF" String msg = index+" \u2209 [0, "+upperBound+')'; throw new IndexOutOfBoundsException(msg); } private static RuntimeException onEmptyStackTopRead() { throw new RuntimeException("Empty stack"); } private static RuntimeException onSeledMutation() { throw new IllegalStateException("Attempt to modify sealed array"); } private void writeObject(ObjectOutputStream os) throws IOException { os.defaultWriteObject(); int N = size; for (int i = 0; i != N; ++i) { Object obj = getImpl(i); os.writeObject(obj); } } private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { is.defaultReadObject(); // It reads size int N = size; if (N > FIELDS_STORE_SIZE) { data = new Object[N - FIELDS_STORE_SIZE]; } for (int i = 0; i != N; ++i) { Object obj = is.readObject(); setImpl(i, obj); } } // Number of data elements private int size; private boolean sealed; private static final int FIELDS_STORE_SIZE = 5; private transient Object f0, f1, f2, f3, f4; private transient Object[] data; }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>'t been filled in for that * module. * * dependencyMap should be filled from leaf to root so that * getTransitiveDepsDeepestFirst can use its results directly. */ private Map<JSModule, Set<JSModule>> dependencyMap = Maps.newHashMap(); /** * Creates a module graph from a list of modules in dependency order. */ public JSModuleGraph(JSModule[] modulesInDepOrder) { moduleDepths = new HashMap<JSModule, Integer>(modulesInDepOrder.length); modulesByDepth = new ArrayList<List<JSModule>>(); for (JSModule module : modulesInDepOrder) { int depth = 0; for (JSModule dep : module.getDependencies()) { Integer depDepth = moduleDepths.get(dep); if (depDepth == null) { throw new ModuleDependenceException(String.format( "Modules not in dependency order: %s preceded %s", module.getName(), dep.getName()), module, dep); } depth = Math.max(depth, depDepth + 1); } moduleDepths.put(module, depth); if (depth == modulesByDepth.size()) { modulesByDepth.add(new ArrayList<JSModule>()); } modulesByDepth.get(depth).add(module); } } /** * Gets an iterable over all modules. */ Iterable<JSModule> getAllModules() { return moduleDepths.keySet(); } /** * Gets the total number of modules. */ int getModuleCount() { return moduleDepths.size(); } /** * Gets the root module. */ JSModule getRootModule() { return Iterables.getOnlyElement(modulesByDepth.get(0)); } /** * Gets the depth of a module. * * @param module A module in this graph * @return The depth of the module */ int getDepth(JSModule module) { return moduleDepths.get(module); } /** * Determines whether this module depends on a given module. Note that a * module never depends on itself, as that dependency would be cyclic. */ public boolean dependsOn(JSModule src, JSModule m) { Set

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS><JSModule> deps = dependencyMap.get(src); if (deps == null) { deps = getTransitiveDepsDeepestFirst(src); dependencyMap.put(src, deps); } return deps.contains(m); } /** * Finds the deepest common dependency of two modules, not including the two * modules themselves. * * @param m1 A module in this graph * @param m2 A module in this graph * @return The deepest common dep of {@code m1} and {@code m2}, or null if * they have no common dependencies */ JSModule getDeepestCommonDependency(JSModule m1, JSModule m2) { int m1Depth = getDepth(m1); int m2Depth = getDepth(m2); // According our definition of depth, the result must have a strictly // smaller depth than either m1 or m2. for (int depth = Math.min(m1Depth, m2Depth) - 1; depth >= 0; depth--) { List<JSModule> modulesAtDepth = modulesByDepth.get(depth); // Look at the modules at this depth in reverse order, so that we use the // original ordering of the modules to break ties (later meaning deeper). for (int i = modulesAtDepth.size() - 1; i >= 0; i--) { JSModule m = modulesAtDepth.get(i); if (dependsOn(m1, m) && dependsOn(m2, m)) { return m; } } } return null; } /** * Finds the deepest common dependency of two modules, including the * modules themselves. * * @param m1 A module in this graph * @param m2 A module in this graph * @return The deepest common dep of {@code m1} and {@code m2}, or null if * they have no common dependencies */ public JSModule getDeepestCommonDependencyInclusive( JSModule m1, JSModule m2) { if (m2 == m1 || dependsOn(m2, m1)) { return m1; } else if (dependsOn(m1, m2

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>)) { return m2; } return getDeepestCommonDependency(m1, m2); } /** Returns the deepest common dependency of the given modules. */ public JSModule getDeepestCommonDependencyInclusive( Collection<JSModule> modules) { Iterator<JSModule> iter = modules.iterator(); JSModule dep = iter.next(); while (iter.hasNext()) { dep = getDeepestCommonDependencyInclusive(dep, iter.next()); } return dep; } /** * Creates an iterable over the transitive dependencies of module {@code m} * in a non-increasing depth ordering. The result does not include the module * {@code m}. * * @param m A module in this graph * @return The transitive dependencies of module {@code m} */ Set<JSModule> getTransitiveDepsDeepestFirst(JSModule m) { Set<JSModule> deps = dependencyMap.get(m); if (deps != null) { return deps; } deps = new TreeSet<JSModule>(new InverseDepthComparator()); addDeps(deps, m); dependencyMap.put(m, deps); return deps; } /** * Adds a module's transitive dependencies to a set. */ private void addDeps(Set<JSModule> deps, JSModule m) { for (JSModule dep : m.getDependencies()) { deps.add(dep); addDeps(deps, dep); } } /** * Replaces any files that are found multiple times with a single instance in * the closest parent module that is common to all modules where it appears. * * JSCompiler normally errors if you attempt to compile modules containing the * same file. This method can be used to remove duplicates before compiling * to avoid such an error. */ public void coalesceDuplicateFiles() { Multimap<String, JSModule> fileRefs = LinkedHashMultimap.create(); for (JSModule module : moduleDepths.keySet()) { for (CompilerInput jsFile : module.getInputs()) { fileRefs.put(jsFile.getName(), module); } } for (String path : fileRefs.keySet()) { Collection<JSModule> ref

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>Modules = fileRefs.get(path); if (refModules.size() > 1) { JSModule depModule = getDeepestCommonDependencyInclusive(refModules); CompilerInput file = refModules.iterator().next().getByName(path); for (JSModule module : refModules) { if (module != depModule) { module.removeByName(path); } } if (!refModules.contains(depModule)) { depModule.add(file); } } } } /** * A module depth comparator that considers a deeper module to be "less than" * a shallower module. Uses module names to consistently break ties. */ private class InverseDepthComparator implements Comparator<JSModule> { public int compare(JSModule m1, JSModule m2) { if (m1 == m2) { return 0; } int d1 = getDepth(m1); int d2 = getDepth(m2); return d2 < d1 ? -1 : d2 == d1 ? m2.getName().compareTo(m1.getName()) : 1; } } /* * Exception class for declaring when the modules being fed into a * JSModuleGraph as input aren't in dependence order, and so can't be * processed for caching of various dependency-related queries. */ protected static class ModuleDependenceException extends IllegalArgumentException { private static final long serialVersionUID = 1; private final JSModule module; private final JSModule dependentModule; protected ModuleDependenceException(String message, JSModule module, JSModule dependentModule) { super(message); this.module = module; this.dependentModule = dependentModule; } public JSModule getModule() { return module; } public JSModule getDependentModule() { return dependentModule; } } }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>/* * Copyright 2005 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * A JavaScript module has a unique name, consists of a list of compiler inputs, * and can depend on other modules. * * * */ public class JSModule { /** Module name */ private final String name; /** Source code inputs */ private final List<CompilerInput> inputs = new ArrayList<CompilerInput>(); /** Modules that this module depends on */ private final List<JSModule> deps = new ArrayList<JSModule>(); /** * Creates an instance. * * @param name A unique name for the module */ public JSModule(String name) { this.name = name; } /** Gets the module name. */ public String getName() { return name; } /** Adds a source file input to this module. */ public void add(JSSourceFile file) { add(new CompilerInput(file)); } /** Adds a source file input to this module. */ public void addFirst(JSSourceFile file) { addFirst(new CompilerInput(file)); } /** Adds a source code input to this module. */ public void add(CompilerInput input) {

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> inputs.add(input); input.setModule(this); } /** Adds a source code input to this module. */ public void addFirst(CompilerInput input) { inputs.add(0, input); input.setModule(this); } /** Adds a source code input to this module directly after other. */ public void addAfter(CompilerInput input, CompilerInput other) { Preconditions.checkState(inputs.contains(other)); inputs.add(inputs.indexOf(other), input); input.setModule(this); } /** Adds a dependency on another module. */ public void addDependency(JSModule dep) { Preconditions.checkState(dep != this); deps.add(dep); } /** Removes all of the inputs from this module. */ public void removeAll() { for (CompilerInput input : inputs) { input.setModule(null); } inputs.clear(); } /** * Gets the list of modules that this module depends on. * * @return A list that may be empty but not null */ public List<JSModule> getDependencies() { return deps; } /** * Returns the transitive closure of dependencies starting from the * dependencies of this module. */ public Set<JSModule> getAllDependencies() { Set<JSModule> allDeps = Sets.newHashSet(deps); List<JSModule> workList = Lists.newArrayList(deps); while (workList.size() > 0) { JSModule module = workList.remove(workList.size() - 1); for (JSModule dep : module.getDependencies()) { if (allDeps.add(dep)) { workList.add(dep); } } } return allDeps; } /** Returns this module and all of its dependencies in one list. */ public Set<JSModule> getThisAndAllDependencies() { Set<JSModule> deps = getAllDependencies(); deps.add(this); return deps; } /** * Gets this module's list of source code inputs. * * @return A list that may be empty but not null */ public List<CompilerInput> getInputs() { return inputs; } /** Returns the input with the

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> Returns the given collection of modules in topological order. * * Note that this will return the modules in the same order if they are * already sorted, and in general, will only change the order as necessary to * satisfy the ordering dependencies. This can be important for cases where * the modules do not properly specify all dependencies. */ public static JSModule[] sortJsModules(Collection<JSModule> modules) { List<JSModule> list = Lists.newArrayList(); Set<JSModule> set = Sets.newHashSet(); for (JSModule module : modules) { addModuleAndDeps(module, list, set, Sets.<JSModule>newHashSet()); } return list.toArray(new JSModule[list.size()]); } /** * Adds the given input and its deps to the given list and set, if they are * not already added, placing dependencies before dependants. */ private static void addInputAndDeps( CompilerInput input, Map<String, CompilerInput> provides, Compiler compiler, List<CompilerInput> list, Set<CompilerInput> set, Set<CompilerInput> inProgress) { if (!set.contains(input)) { if (inProgress.contains(input)) { throw new IllegalArgumentException( "Circular dependency involving input: " + input.getName()); } inProgress.add(input); for (String require : input.getRequires(compiler)) { if (provides.containsKey(require)) { addInputAndDeps(provides.get(require), provides, compiler, list, set, inProgress); } } list.add(input); set.add(input); } } /** * Adds the given module and its deps to the given list and set, if they are * not already added, placing dependencies before dependants. */ private static void addModuleAndDeps( JSModule module, List<JSModule> list, Set<JSModule> set, Set<JSModule> inProgress) { if (!set.contains(module)) { if (inProgress.contains(module)) { throw new IllegalArgumentException( "Circular dependency involving module: " + module.getName()); } inProgress.add(module); for (JSModule dep : module.getDependencies()) {

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> addModuleAndDeps(dep, list, set, inProgress); } list.add(module); set.add(module); } } }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> data structures cached by this table. */ private static class MemoizedData { private Map<Node, Scope> scopes = Maps.newHashMap(); } //---------------------------------------------------------------------------- // Verification of consistency. Only for tests. /** * Check that this symbol table has been kept up to date. Compiler warnings * will be emitted if anything is wrong. * @param expectedRoot The root of the expected AST. * @param actualRoot The root of the actual AST used with this symbol table. */ void verify(Node expectedRoot, Node actualRoot) { VerifyingCallback callback = new VerifyingCallback( expectedRoot, actualRoot); callback.verify(); } /** * A callback that traverses an AST root and builds all the * secondary data structures for it. */ private class VerifyingCallback implements ScopedCallback { private final List<Scope> expectedScopes = Lists.newArrayList(); private final List<Scope> actualScopes = Lists.newArrayList(); private boolean collectingExpected = true; private final Node actualRoot; private final Node expectedRoot; private VerifyingCallback(Node expectedRoot, Node actualRoot) { this.actualRoot = actualRoot; this.expectedRoot = expectedRoot; } @Override public boolean shouldTraverse( NodeTraversal nodeTraversal, Node n, Node parent) { return true; } @Override public void visit(NodeTraversal t, Node n, Node parent) {} @Override public void enterScope(NodeTraversal t) {} @Override public void exitScope(NodeTraversal t) { if (collectingExpected) { expectedScopes.add(t.getScope()); } else { actualScopes.add(t.getScope()); } } private void verify() { if (cache == null) { // The symbol table was never used, so no need to check anything. return; } if (!cache.scopes.isEmpty()) { verifyScopes(); } } private void verifyScopes() { collectingExpected = true; NodeTraversal.traverse(compiler, expectedRoot, this); collectingExpected = false; (new NodeTraversal(compiler, this, SymbolTable.this)) .traverse(actualRoot); // This must be true unless something went horribly, horribly wrong.

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> Preconditions.checkState(expectedScopes.size() == actualScopes.size()); for (int i = 0; i < expectedScopes.size(); i++) { Scope expectedScope = expectedScopes.get(i); Scope actualScope = actualScopes.get(i); if (!checkNodesMatch(expectedScope.getRootNode(), actualScope.getRootNode())) { compiler.report( JSError.make( SCOPE_MISMATCH, expectedScope.getRootNode().toStringTree(), actualScope.getRootNode().toStringTree())); continue; } if (expectedScope.getVarCount() != actualScope.getVarCount()) { compiler.report( JSError.make( VARIABLE_COUNT_MISMATCH, Integer.toString(expectedScope.getVarCount()), Integer.toString(actualScope.getVarCount()))); } else { Iterator<Var> it = expectedScope.getVars(); while (it.hasNext()) { Var var = it.next(); Scope.Var actualVar = actualScope.getVar(var.getName()); if (actualVar == null || expectedScope.getVar(var.getName()) != var) { compiler.report( JSError.make(MISSING_VARIABLE, var.getName())); } else if ( !checkNodesMatch( var.getNameNode(), actualVar.getNameNode()) || !isNodeAttached(actualVar.getNameNode())) { compiler.report( JSError.make(MOVED_VARIABLE, var.getName())); } } } } } /** * Check that the two nodes have the same relative position in the tree. */ private boolean checkNodesMatch(Node nodeA, Node nodeB) { Node currentA = nodeA; Node currentB = nodeB; while (currentA != null && currentB != null) { if (currentA.getType() != currentB.getType() || !currentA.isEquivalentTo(currentB)) { return false; } currentA = currentA.getParent(); currentB = currentB.getParent(); } return currentA == null && currentB == null; } private boolean isNodeAttached(Node node) { // Make sure the cached var is still attached. for (Node current = node; current != null; current

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> node.addChildToBack(c); } if (skipCount > 0) { int[] skipIndexes = new int[skipCount]; int i = 0; int j = 0; for (Node child : node.children()) { if (child.getType() == Token.EMPTY) { node.removeChild(child); skipIndexes[j] = i; j++; } i++; } node.putProp(Node.SKIP_INDEXES_PROP, skipIndexes); } return node; } @Override Node processAssignment(Assignment assignmentNode) { return processInfixExpression(assignmentNode); } @Override Node processAstRoot(AstRoot rootNode) { Node node = new ScriptOrFnNode(Token.SCRIPT); for (com.google.javascript.jscomp.mozilla.rhino.Node child : rootNode) { node.addChildToBack(transform((AstNode)child)); } parseDirectives(node); return node; } /** * Parse the directives, encode them in the AST, and remove their nodes. * * For information on ES5 directives, see section 14.1 of * Ecma-262, Edition 5. * * It would be nice if Rhino would eventually take care of this for * us, but right now their directive-processing is a one-off. */ private void parseDirectives(Node node) { // Remove all the directives, and encode them in the AST. Set<String> directives = null; while (isDirective(node.getFirstChild())) { String directive = node.removeFirstChild().getFirstChild().getString(); if (directives == null) { directives = Sets.newHashSet(directive); } else { directives.add(directive); } } if (directives != null) { node.setDirectives(directives); } } private boolean isDirective(Node n) { if (n == null) return false; int nType = n.getType(); return (nType == Token.EXPR_RESULT || nType == Token.EXPR_VOID) && n.getFirstChild().getType() == Token.STRING && ALLOWED_DIRECTIVES.contains(n.getFirstChild

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> source = getSource(); String sourceExcerpt = source == null ? null : excerpt.get( source, error.sourceName, error.lineNumber, excerptFormatter); // formatting the message StringBuilder b = new StringBuilder(); if (error.sourceName != null) { b.append(error.sourceName); if (error.lineNumber > 0) { b.append(':'); b.append(error.lineNumber); } b.append(": "); } b.append(getLevelName(warning ? CheckLevel.WARNING : CheckLevel.ERROR)); b.append(" - "); b.append(error.description); b.append('\n'); if (sourceExcerpt != null) { b.append(sourceExcerpt); b.append('\n'); int charno = error.getCharno(); // padding equal to the excerpt and arrow at the end if (excerpt.equals(LINE) && 0 <= charno && charno < sourceExcerpt.length()) { for (int i = 0; i < charno; i++) { char c = sourceExcerpt.charAt(i); if (Character.isWhitespace(c)) { b.append(c); } else { b.append(' '); } } b.append("^\n"); } } return b.toString(); } /** * Formats a region by appending line numbers in front, e.g. * <pre> 9| if (foo) { * 10| alert('bar'); * 11| }</pre> * and return line excerpt without any modification. */ static class LineNumberingFormatter implements ExcerptFormatter { public String formatLine(String line, int lineNumber) { return line; } public String formatRegion(Region region) { if (region == null) { return null; } String code = region.getSourceExcerpt(); if (code.length() == 0) { return null; } // max length of the number display int numberLength = Integer.toString(region.getEndingLineNumber()) .length(); // formatting StringBuilder builder = new StringBuilder(code.length() * 2); int

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> /** * Gets the number of properties of this object. */ @Override public int getPropertiesCount() { ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype == null) { return this.properties.size(); } int localCount = 0; for (String property : properties.keySet()) { if (!implicitPrototype.hasProperty(property)) { localCount++; } } return implicitPrototype.getPropertiesCount() + localCount; } @Override public boolean hasProperty(String propertyName) { if (properties.get(propertyName) != null) { return true; } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.hasProperty(propertyName); } return false; } @Override public boolean hasOwnProperty(String propertyName) { return properties.get(propertyName) != null; } @Override public Set<String> getOwnPropertyNames() { return properties.keySet(); } @Override public boolean isPropertyTypeDeclared(String property) { Property p = properties.get(property); if (p == null) { ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.isPropertyTypeDeclared(property); } // property does not exist return false; } return !p.inferred; } @Override protected void collectPropertyNames(Set<String> props) { for (String prop : properties.keySet()) { props.add(prop); } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { implicitPrototype.collectPropertyNames(props); } } @Override public boolean isPropertyTypeInferred(String property) { Property p = properties.get(property); if (p == null) { ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.isPropertyTypeInferred(property); } // property does not exist return false; } return p.inferred; } @Override public JSType getPropertyType(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.type; } ObjectType implicitPrototype = getImplicit

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> return; } // resolving component by component for (int i = 1; i < componentNames.length; i++) { ObjectType parentClass = ObjectType.cast(value); if (parentClass == null) { handleUnresolvedType(t); return; } if (componentNames[i].length() == 0) { handleUnresolvedType(t); return; } value = parentClass.getPropertyType(componentNames[i]); } // last component of the chain if (value instanceof FunctionType) { FunctionType functionType = (FunctionType)value; if (functionType.isConstructor() || functionType.isInterface()) { setReferencedType(functionType.getInstanceType(), t, enclosing); } else { handleUnresolvedType(t); } } else if (value instanceof EnumType) { setReferencedType(((EnumType) value).getElementsType(), t, enclosing); } else { handleUnresolvedType(t); } } private void setReferencedType(ObjectType type, ErrorReporter t, StaticScope<JSType> enclosing) { referencedType = type; checkEnumElementCycle(t); setResolvedTypeInternal(referencedType); } private void handleTypeCycle(ErrorReporter t) { referencedType = registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE); t.warning("Cycle detected in inheritance chain of type " + reference, sourceName, lineno, null, charno); setResolvedTypeInternal(referencedType); } private void checkEnumElementCycle(ErrorReporter t) { if (referencedType instanceof EnumElementType && ((EnumElementType) referencedType).getPrimitiveType() == this) { handleTypeCycle(t); } } // Warns about this type being unresolved iff it's not a forward-declared // type name. private void handleUnresolvedType(ErrorReporter t) { if (!registry.isForwardDeclaredType(reference) && !forgiving && registry.isLastGeneration()) { t.warning("Unknown type " + reference, sourceName, lineno, null, charno); } else { referencedType = registry.getNativeObjectType( JSTypeNative.CHECKED_UNKNOWN_TYPE); } setResolvedType

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.jstype.FunctionType; import com.google.javascript.rhino.jstype.JSType; import com.google.javascript.rhino.jstype.ObjectType; import java.nio.charset.Charset; /** * A code generator that outputs type annotations for functions and * constructors. * */ class TypedCodeGenerator extends CodeGenerator { TypedCodeGenerator(CodeConsumer consumer, Charset outputCharset) { super(consumer, outputCharset, true); } @Override void add(Node n, Context context) { Node parent = n.getParent(); if (parent.getType() == Token.BLOCK || parent.getType() == Token.SCRIPT) { if (n.getType() == Token.FUNCTION) { add(getFunctionAnnotation(n)); } else if (n.getType() == Token.EXPR_RESULT && n.getFirstChild().getType() == Token.ASSIGN) { Node rhs = n.getFirstChild().getFirstChild(); add(getTypeAnnotation(rhs)); } else if (n.getType() == Token.VAR && n.getFirstChild().getFirstChild() != null && n.getFirstChild().getFirstChild().getType() == Token.FUNCTION) { add(getFunctionAnnotation(n.getFirstChild().getFirstChild())); } } super.add(n, context); } private String getTypeAnnotation(Node node) { JSType type = node.getJSType();

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> private VariableMap anonymousFunctionNameMap = null; /** Fully qualified function names and globally unique ids */ private FunctionNames functionNames = null; public DefaultPassConfig(CompilerOptions options) { super(options); } @Override State getIntermediateState() { return new State( cssNames == null ? null : Maps.newHashMap(cssNames), exportedNames == null ? null : Collections.unmodifiableSet(exportedNames), crossModuleIdGenerator, variableMap, propertyMap, anonymousFunctionNameMap, functionNames); } @Override void setIntermediateState(State state) { this.cssNames = state.cssNames == null ? null : Maps.newHashMap(state.cssNames); this.exportedNames = state.exportedNames == null ? null : Sets.newHashSet(state.exportedNames); this.crossModuleIdGenerator = state.crossModuleIdGenerator; this.variableMap = state.variableMap; this.propertyMap = state.propertyMap; this.anonymousFunctionNameMap = state.anonymousFunctionNameMap; this.functionNames = state.functionNames; } @Override protected List<PassFactory> getChecks() { List<PassFactory> checks = Lists.newArrayList(); if (options.nameAnonymousFunctionsOnly) { if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.MAPPED) { checks.add(nameMappedAnonymousFunctions); } else if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.UNMAPPED) { checks.add(nameUnmappedAnonymousFunctions); } return checks; } if (options.checkSuspiciousCode) { checks.add(suspiciousCode); } if (options.checkControlStructures) { checks.add(checkControlStructures); } if (options.checkRequires.isOn()) { checks.add(checkRequires); } if (options.checkProvides.isOn()) { checks.add(checkProvides); } // The following passes are more like "preprocessor" passes. // It's important that they run before most checking passes. // Perhaps this method should be renamed? if (options.generateExports) { checks.add(generateExports); } if (options.exportTestFunctions) {

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> checks.add(exportTestFunctions); } if (options.closurePass) { checks.add(closurePrimitives.makeOneTimePass()); } if (options.closurePass && options.checkMissingGetCssNameLevel.isOn()) { checks.add(closureCheckGetCssName); } if (options.closurePass) { checks.add(closureReplaceGetCssName); } if (options.syntheticBlockStartMarker != null) { // This pass must run before the first fold constants pass. checks.add(createSyntheticBlocks); } // All passes must run the variable check. This synthesizes // variables later so that the compiler doesn't crash. It also // checks the externs file for validity. If you don't want to warn // about missing variable declarations, we shut that specific // error off. WarningsGuard warningsGuard = options.getWarningsGuard(); if (!options.checkSymbols && (warningsGuard == null || !warningsGuard.disables( DiagnosticGroups.CHECK_VARIABLES))) { options.setWarningLevel(DiagnosticGroups.CHECK_VARIABLES, CheckLevel.OFF); } checks.add(checkVars); if (options.checkShadowVars.isOn()) { checks.add(checkShadowVars); } if (options.aggressiveVarCheck.isOn()) { checks.add(checkVariableReferences); } // This pass should run before types are assigned. if (options.processObjectPropertyString) { checks.add(objectPropertyStringPreprocess); } // DiagnosticGroups override the plain checkTypes option. if (options.enables(DiagnosticGroups.CHECK_TYPES)) { options.checkTypes = true; } else if (options.disables(DiagnosticGroups.CHECK_TYPES)) { options.checkTypes = false; } // Type-checking already does more accurate method arity checking, so don't // do legacy method arity checking unless checkTypes is OFF. if (options.checkTypes) { checks.add(resolveTypes.makeOneTimePass()); checks.add(inferTypes.makeOneTimePass()); checks.add(checkTypes.makeOneTimePass()); } else { if (options.checkFunctions.isOn()) {

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> checks.add(checkFunctions); } if (options.checkMethods.isOn()) { checks.add(checkMethods); } } if (options.checkUnreachableCode.isOn() || (options.checkTypes && options.checkMissingReturn.isOn())) { checks.add(checkControlFlow); } // CheckAccessControls only works if check types is on. if (options.enables(DiagnosticGroups.ACCESS_CONTROLS) && options.checkTypes) { checks.add(checkAccessControls); } if (options.checkGlobalNamesLevel.isOn()) { checks.add(checkGlobalNames); } if (options.checkUndefinedProperties.isOn() || options.checkUnusedPropertiesEarly) { checks.add(checkSuspiciousProperties); } if (options.checkCaja || options.checkEs5Strict) { checks.add(checkStrictMode); } // Defines in code always need to be processed. checks.add(processDefines); if (options.instrumentationTemplate != null || options.recordFunctionInformation) { checks.add(computeFunctionNames); } assertAllOneTimePasses(checks); return checks; } @Override protected List<PassFactory> getOptimizations() { List<PassFactory> passes = Lists.newArrayList(); // TODO(nicksantos): The order of these passes makes no sense, and needs // to be re-arranged. if (options.runtimeTypeCheck) { passes.add(runtimeTypeCheck); } passes.add(createEmptyPass("beforeStandardOptimizations")); if (!options.idGenerators.isEmpty()) { passes.add(replaceIdGenerators); } // Optimizes references to the arguments variable. if (options.optimizeArgumentsArray) { passes.add(optimizeArgumentsArray); } // Remove all parameters that are constants or unused. if (options.optimizeParameters) { passes.add(removeUselessParameters); } // Abstract method removal works best on minimally modified code, and also // only needs to run once. if (options.closurePass && options.removeAbstractMethods) { passes.add(removeAbstractMethods); } // Collapsing properties can undo constant

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> inlining, so we do this before // the main optimization loop. if (options.collapseProperties) { passes.add(collapseProperties); } // Tighten types based on actual usage. if (options.tightenTypes) { passes.add(tightenTypesBuilder); } // Property disambiguation should only run once and needs to be done // soon after type checking, both so that it can make use of type // information and so that other passes can take advantage of the renamed // properties. if (options.disambiguateProperties) { passes.add(disambiguateProperties); } if (options.computeFunctionSideEffects) { passes.add(markPureFunctions); } else if (options.markNoSideEffectCalls) { // TODO(user) The properties that this pass adds to CALL and NEW // AST nodes increase the AST's in-memory size. Given that we are // already running close to our memory limits, we could run into // trouble if we end up using the @nosideeffects annotation a lot // or compute @nosideeffects annotations by looking at function // bodies. It should be easy to propagate @nosideeffects // annotations as part of passes that depend on this property and // store the result outside the AST (which would allow garbage // collection once the pass is done). passes.add(markNoSideEffectCalls); } if (options.chainCalls) { passes.add(chainCalls); } // Constant checking must be done after property collapsing because // property collapsing can introduce new constants (e.g. enum values). if (options.inlineConstantVars) { passes.add(checkConsts); } // The Caja library adds properties to Object.prototype, which breaks // most for-in loops. This adds a check to each loop that skips // any property matching /___$/. if (options.ignoreCajaProperties) { passes.add(ignoreCajaProperties); } assertAllOneTimePasses(passes); if (options.smartNameRemoval || options.reportPath != null) { passes.addAll(getCodeRemovingPasses()); passes.add(smartNamePass); } // TODO(user): This forces a

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> first crack at crossModuleCodeMotion // before devirtualization. Once certain functions are devirtualized, // it confuses crossModuleCodeMotion ability to recognized that // it is recursive. // TODO(user): This is meant for a temporary quick win. // In the future, we might want to improve our analysis in // CrossModuleCodeMotion so we don't need to do this. if (options.crossModuleCodeMotion) { passes.add(crossModuleCodeMotion); } // Method devirtualization benefits from property disambiguiation so // it should run after that pass but before passes that do // optimizations based on global names (like cross module code motion // and inline functions). Smart Name Removal does better if run before // this pass. if (options.devirtualizePrototypeMethods) { passes.add(devirtualizePrototypeMethods); } if (options.customPasses != null) { passes.add(getCustomPasses( CustomPassExecutionTime.BEFORE_OPTIMIZATION_LOOP)); } passes.add(createEmptyPass("beforeMainOptimizations")); passes.addAll(getMainOptimizationLoop()); passes.add(createEmptyPass("beforeModuleMotion")); if (options.crossModuleCodeMotion) { passes.add(crossModuleCodeMotion); } if (options.crossModuleMethodMotion) { passes.add(crossModuleMethodMotion); } passes.add(createEmptyPass("afterModuleMotion")); // Some optimizations belong outside the loop because running them more // than once would either have no benefit or be incorrect. if (options.customPasses != null) { passes.add(getCustomPasses( CustomPassExecutionTime.AFTER_OPTIMIZATION_LOOP)); } if (options.flowSensitiveInlineVariables) { passes.add(flowSensitiveInlineVariables); // After inlining some of the variable uses, some variables are unused. // Re-run remove unused vars to clean it up. if (options.removeUnusedVars) { passes.add(removeUnusedVars); } } if (options.collapseAnonymousFunctions) { passes.add(collapseAnonymousFunctions); } // Move functions before extracting prototype member declarations. if (options.moveFunctionDeclarations) { passes

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>.add(moveFunctionDeclarations); } if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.MAPPED) { passes.add(nameMappedAnonymousFunctions); } // The mapped name anonymous function pass makes use of information that // the extract prototype member declarations pass removes so the former // happens before the latter. // // Extracting prototype properties screws up the heuristic renaming // policies, so never run it when those policies are requested. if (options.extractPrototypeMemberDeclarations && (options.propertyRenaming != PropertyRenamingPolicy.HEURISTIC && options.propertyRenaming != PropertyRenamingPolicy.AGGRESSIVE_HEURISTIC)) { passes.add(extractPrototypeMemberDeclarations); } if (options.coalesceVariableNames) { passes.add(coalesceVariableNames); } if (options.ambiguateProperties && (options.propertyRenaming == PropertyRenamingPolicy.ALL_UNQUOTED)) { passes.add(ambiguateProperties); } if (options.propertyRenaming != PropertyRenamingPolicy.OFF) { passes.add(renameProperties); } // Reserve global names added to the "windows" object. if (options.reserveRawExports) { passes.add(gatherRawExports); } // This comes after property renaming because quoted property names must // not be renamed. if (options.convertToDottedProperties) { passes.add(convertToDottedProperties); } // Property renaming must happen before this pass runs since this // pass may convert dotted properties into quoted properties. It // is beneficial to run before alias strings, alias keywords and // variable renaming. if (options.rewriteFunctionExpressions) { passes.add(rewriteFunctionExpressions); } // This comes after converting quoted property accesses to dotted property // accesses in order to avoid aliasing property names. if (!options.aliasableStrings.isEmpty() || options.aliasAllStrings) { passes.add(aliasStrings); } if (options.aliasExternals) { passes.add(aliasExternals); } if (options.aliasKeywords) { passes.add(aliasKeywords); } if (options.collapseVariableDeclarations) { passes.add(collapseVariableDeclarations);

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> } passes.add(denormalize); if (options.instrumentationTemplate != null) { passes.add(instrumentFunctions); } if (options.variableRenaming != VariableRenamingPolicy.ALL) { // If we're leaving some (or all) variables with their old names, // then we need to undo any of the markers we added for distinguishing // local variables ("$$1"). passes.add(invertContextualRenaming); } if (options.variableRenaming != VariableRenamingPolicy.OFF) { passes.add(renameVars); } // This pass should run after names stop changing. if (options.processObjectPropertyString) { passes.add(objectPropertyStringPostprocess); } if (options.labelRenaming) { passes.add(renameLabels); } if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.UNMAPPED) { passes.add(nameUnmappedAnonymousFunctions); } // Safety check if (options.checkSymbols) { passes.add(sanityCheckVars); } return passes; } /** Creates the passes for the main optimization loop. */ private List<PassFactory> getMainOptimizationLoop() { List<PassFactory> passes = Lists.newArrayList(); if (options.inlineGetters) { passes.add(inlineGetters); } passes.addAll(getCodeRemovingPasses()); if (options.inlineFunctions || options.inlineLocalFunctions) { passes.add(inlineFunctions); } if (options.removeUnusedVars) { if (options.deadAssignmentElimination) { passes.add(deadAssignmentsElimination); } passes.add(removeUnusedVars); } assertAllLoopablePasses(passes); return passes; } /** Creates several passes aimed at removing code. */ private List<PassFactory> getCodeRemovingPasses() { List<PassFactory> passes = Lists.newArrayList(); if (options.inlineVariables || options.inlineLocalVariables) { passes.add(inlineVariables); } else if (options.inlineConstantVars) { passes.add(inlineConstants); } if (options.removeConstantExpressions) { passes.add(removeConstantExpressions); } if

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> (options.foldConstants) { // These used to be one pass. passes.add(minimizeExitPoints); passes.add(foldConstants); } if (options.removeDeadCode) { passes.add(removeUnreachableCode); } if (options.removeUnusedPrototypeProperties) { passes.add(removeUnusedPrototypeProperties); } assertAllLoopablePasses(passes); return passes; } /** * Checks for code that is probably wrong (such as stray expressions). */ // TODO(bolinfest): Write a CompilerPass for this. final PassFactory suspiciousCode = new PassFactory("suspiciousCode", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { List<Callback> sharedCallbacks = Lists.newArrayList(); sharedCallbacks.add(new CheckAccidentalSemicolon(CheckLevel.WARNING)); sharedCallbacks.add(new CheckSideEffects(CheckLevel.WARNING)); if (options.checkGlobalThisLevel.isOn()) { sharedCallbacks.add( new CheckGlobalThis(compiler, options.checkGlobalThisLevel)); } return combineChecks(compiler, sharedCallbacks); } }; /** Verify that all the passes are one-time passes. */ private void assertAllOneTimePasses(List<PassFactory> passes) { for (PassFactory pass : passes) { Preconditions.checkState(pass.isOneTimePass()); } } /** Verify that all the passes are multi-run passes. */ private void assertAllLoopablePasses(List<PassFactory> passes) { for (PassFactory pass : passes) { Preconditions.checkState(!pass.isOneTimePass()); } } /** Checks for validity of the control structures. */ private final PassFactory checkControlStructures = new PassFactory("checkControlStructures", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new ControlStructureCheck(compiler); } }; /** Checks that all constructed classes are goog.require()d. */ private final PassFactory checkRequires = new PassFactory("checkRequires", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CheckRequiresForConstructors(compiler, options.checkRequires

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>(AbstractCompiler compiler) { return new GlobalTypeResolver(compiler); } }; /** Rusn type inference. */ private final PassFactory inferTypes = new PassFactory("inferTypes", false) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node root) { Preconditions.checkNotNull(topScope); Preconditions.checkNotNull(typedScopeCreator); makeTypeInference(compiler).process(externs, root); } }; } }; /** Checks type usage */ private final PassFactory checkTypes = new PassFactory("checkTypes", false) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node root) { Preconditions.checkNotNull(topScope); Preconditions.checkNotNull(typedScopeCreator); TypeCheck check = makeTypeCheck(compiler); check.process(externs, root); compiler.getErrorManager().setTypedPercent(check.getTypedPercent()); } }; } }; /** * Checks possible execution paths of the program for problems: missing return * statements and dead code. */ private final PassFactory checkControlFlow = new PassFactory("checkControlFlow", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { List<Callback> callbacks = Lists.newArrayList(); if (options.checkUnreachableCode.isOn()) { callbacks.add( new CheckUnreachableCode(compiler, options.checkUnreachableCode)); } if (options.checkMissingReturn.isOn() && options.checkTypes) { callbacks.add( new CheckMissingReturn(compiler, options.checkMissingReturn)); } return combineChecks(compiler, callbacks); } }; /** Checks access controls. Depends on type-inference. */ private final PassFactory checkAccessControls = new PassFactory("checkAccessControls", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CheckAccessControls(compiler); } }; /** Executes the given callbacks with a {@link CombinedCompilerPass}. */ private static CompilerPass combineChecks(AbstractCompiler compiler, List<Callback

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>/* * Copyright 2004 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.rhino.Node; /** * Abstracted consumer of the CodeGenerator output. * * @see CodeGenerator * @see CodePrinter * @see InlineCostEstimator * * * */ abstract class CodeConsumer { boolean statementNeedsEnded = false; boolean statementStarted = false; boolean sawFunction = false; /** * Starts the source mapping for the given * node at the current position. */ void startSourceMapping(Node node) { } /** * Finishes the source mapping for the given * node at the current position. */ void endSourceMapping(Node node) { } /** * Generates the source map from the given code consumer, * appending the information it saved to the SourceMap * object given. */ void generateSourceMap(SourceMap map){ } /** * Returns the current length of the buffer in which * the generated code is being placed. */ abstract int getCurrentBufferLength(); /** * Returns the current character position on the current * line in the generated code. */ abstract int getCurrentCharIndex(); /** * Returns the current line in the generated code. */ abstract int getCurrentLineIndex(); /** * Provides a means of interrupting the CodeGenerator. Derived classes should * return false to stop further processing. */ boolean continueProcessing() { return true; } /** * Retrieve the last character of the last string sent to append. */ abstract char getLastChar(); void addIdentifier(String identifier) { add

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>(identifier); } /** * Appends a string to the code, keeping track of the current line length. * * NOTE: the string must be a complete token--partial strings or * partial regexes will run the risk of being split across lines. * * Do not directly append newlines with this method. Instead use * {@link #startNewLine}. */ abstract void append(String str); void appendBlockStart() { append("{"); } void appendBlockEnd() { append("}"); } void startNewLine() { } void maybeLineBreak() { maybeCutLine(); } void maybeCutLine() { } void endLine() { } void notePreferredLineBreak() { } void beginBlock() { if (statementNeedsEnded) { append(";"); maybeLineBreak(); } appendBlockStart(); endLine(); statementNeedsEnded = false; } void endBlock() { endBlock(false); } void endBlock(boolean statementContext) { appendBlockEnd(); if (statementContext) { endLine(); } statementNeedsEnded = false; } void listSeparator() { add(","); maybeLineBreak(); } /** * Indicates the end of a statement and a ';' may need to be added. * But we don't add it now, in case we're at the end of a block (in which * case we don't have to add the ';'). * See maybeEndStatement() */ void endStatement() { endStatement(false); } void endStatement(boolean needSemiColon) { if (needSemiColon) { append(";"); maybeLineBreak(); statementNeedsEnded = false; } else if (statementStarted) { statementNeedsEnded = true; } } /** * This is to be called when we're in a statement. If the prev statement * needs to be ended, add a ';'. */ void maybeEndStatement() { // Add a ';' if we need to. if (statementNeedsEnded) { append(";"); maybeLineBreak(); endLine(); statementNeedsEnded = false; } statementStarted = true; } void endFunction() { endFunction(false

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>); } void endFunction(boolean statementContext) { sawFunction = true; if (statementContext) { endLine(); } } void beginCaseBody() { append(":"); } void endCaseBody() { } void add(String newcode) { maybeEndStatement(); if (newcode.length() == 0) { return; } char c = newcode.charAt(0); if ((isWordChar(c) || c == '\\') && isWordChar(getLastChar())) { // need space to separate. This is not pretty printing. // For example: "return foo;" append(" "); } append(newcode); } void appendOp(String op, boolean binOp) { append(op); } void addOp(String op, boolean binOp) { maybeEndStatement(); char first = op.charAt(0); char prev = getLastChar(); if ((first == '+' || first == '-') && prev == first) { // This is not pretty printing. This is to prevent misparsing of // things like "x + ++y" or "x++ + ++y" append(" "); } else if (Character.isLetter(first) && isWordChar(prev)) { // Make sure there is a space after e.g. instanceof , typeof append(" "); } else if (prev == '-' && first == '>') { // Make sure that we don't emit --> append(" "); } // Allow formating around the operator. appendOp(op, binOp); // Line breaking after an operator is always safe. Line breaking before an // operator on the other hand is not. We only line break after a bin op // because it looks strange. if (binOp) { maybeCutLine(); } } void addNumber(double x) { // This is not pretty printing. This is to prevent misparsing of x- -4 as // x--4 (which is a syntax error). char prev = getLastChar(); if (x < 0 && prev == '-') { add(" "); } if ((long) x == x) { long value = (long) x; long mantissa = value; int exp =

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> 0; if (x >= 100) { while (mantissa / 10 * Math.pow(10, exp + 1) == value) { mantissa /= 10; exp++; } } if (exp > 2) { add(Long.toString(mantissa) + "E" + Integer.toString(exp)); } else { add(Long.toString(value)); } } else { add(String.valueOf(x)); } } static boolean isWordChar(char ch) { return (ch == '_' || ch == '$' || Character.isLetterOrDigit(ch)); } /** * If the body of a for loop or the then clause of an if statement has * a single statement, should it be wrapped in a block? Doing so can * help when pretty-printing the code, and permits putting a debugging * breakpoint on the statement inside the condition. * * @return {@boolean true} if such expressions should be wrapped */ boolean shouldPreserveExtraBlocks() { return false; } }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> { JSType newAlternate = alternate.resolve(t, scope); changed |= (alternate != newAlternate); resolvedTypes.add(alternate); } if (changed) { Set<JSType> newAlternates = resolvedTypes.build(); Preconditions.checkState(newAlternates.hashCode() == this.hashcode); alternates = newAlternates; } return this; } }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> ZEROS_AFTER_54: // x1.1 -> x1 + 1 (round up) // x0.1 -> x0 (round down) if (bit54 & bit53) sum += 1.0; sum *= factor; break; case MIXED_AFTER_54: // x.100...1.. -> x + 1 (round up) // x.0anything -> x (round down) if (bit54) sum += 1.0; sum *= factor; break; } } /* We don't worry about inaccurate numbers for any other base. */ } return sum; } public static String escapeString(String s) { return escapeString(s, '"'); } /** * For escaping strings printed by object and array literals; not quite * the same as 'escape.' */ public static String escapeString(String s, char escapeQuote) { if (!(escapeQuote == '"' || escapeQuote == '\'')) Kit.codeBug(); StringBuffer sb = null; for(int i = 0, L = s.length(); i != L; ++i) { int c = s.charAt(i); if (' ' <= c && c <= '~' && c != escapeQuote && c != '\\') { // an ordinary print character (like C isprint()) and not " // or \ . if (sb != null) { sb.append((char)c); } continue; } if (sb == null) { sb = new StringBuffer(L + 3); sb.append(s); sb.setLength(i); } int escape = -1; switch (c) { case '\b': escape = 'b'; break; case '\f': escape = 'f'; break; case '\n': escape = 'n'; break; case '\r': escape = 'r'; break; case '\t': escape = 't'; break; case 0xb: escape = 'v'; break; // Java lacks \v. case ' ': escape = ' '; break; case '\\': escape = '\\

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>'; break; } if (escape >= 0) { // an \escaped sort of character sb.append('\\'); sb.append((char)escape); } else if (c == escapeQuote) { sb.append('\\'); sb.append(escapeQuote); } else { int hexSize; if (c < 256) { // 2-digit hex sb.append("\\x"); hexSize = 2; } else { // Unicode. sb.append("\\u"); hexSize = 4; } // append hexadecimal form of c left-padded with 0 for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) { int digit = 0xf & (c >> shift); int hc = (digit < 10) ? '0' + digit : 'a' - 10 + digit; sb.append((char)hc); } } } return (sb == null) ? s : sb.toString(); } static boolean isValidIdentifierName(String s) { int L = s.length(); if (L == 0) return false; if (!Character.isJavaIdentifierStart(s.charAt(0))) return false; for (int i = 1; i != L; ++i) { if (!Character.isJavaIdentifierPart(s.charAt(i))) return false; } return !TokenStream.isKeyword(s); } /** * Convert the value to a string. * * See ECMA 9.8. */ public static String toString(Object val) { for (;;) { if (val == null) { return "null"; } if (val instanceof String) { return (String)val; } if (val instanceof Number) { // XXX should we just teach NativeNumber.stringValue() // about Numbers? return numberToString(((Number)val).doubleValue(), 10); } return val.toString(); } } public static String numberToString(double d, int base) { if (d != d) return "NaN"; if (d == Double.POSITIVE_INFINITY) return "Infinity

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>"; if (d == Double.NEGATIVE_INFINITY) return "-Infinity"; if (d == 0.0) return "0"; if ((base < 2) || (base > 36)) { throw Context.reportRuntimeError1( "msg.bad.radix", Integer.toString(base)); } if (base != 10) { return DToA.JS_dtobasestr(base, d); } else { StringBuffer result = new StringBuffer(); DToA.JS_dtostr(result, DToA.DTOSTR_STANDARD, 0, d); return result.toString(); } } /** * If str is a decimal presentation of Uint32 value, return it as long. * Othewise return -1L; */ public static long testUint32String(String str) { // The length of the decimal string representation of // UINT32_MAX_VALUE, 4294967296 final int MAX_VALUE_LENGTH = 10; int len = str.length(); if (1 <= len && len <= MAX_VALUE_LENGTH) { int c = str.charAt(0); c -= '0'; if (c == 0) { // Note that 00,01 etc. are not valid Uint32 presentations return (len == 1) ? 0L : -1L; } if (1 <= c && c <= 9) { long v = c; for (int i = 1; i != len; ++i) { c = str.charAt(i) - '0'; if (!(0 <= c && c <= 9)) { return -1; } v = 10 * v + c; } // Check for overflow if ((v >>> 32) == 0) { return v; } } } return -1; } static boolean isSpecialProperty(String s) { return s.equals("__proto__") || s.equals("__parent__"); } // ------------------ // Statements // ------------------ public static String getMessage0(String messageId) { return getMessage(messageId, null);

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; /** * An abstract representation of a JavaScript source file, as input to * JSCompiler. * * @author nicksantos@google.com (Nick Santos) * */ public class JSSourceFile extends SourceFile { public static JSSourceFile fromFile(String fileName, Charset charSet) { return new JSSourceFile(SourceFile.fromFile(fileName, charSet)); } public static JSSourceFile fromFile(String fileName) { return new JSSourceFile(SourceFile.fromFile(fileName, Charsets.UTF_8)); } public static JSSourceFile fromFile(File file, Charset charSet) { return new JSSourceFile(SourceFile.fromFile(file, charSet)); } public static JSSourceFile fromFile(File file) { return new JSSourceFile(SourceFile.fromFile(file, Charsets.UTF_8)); } public static JSSourceFile fromCode(String fileName, String code) { return new JSSourceFile(SourceFile.fromCode(fileName, code)); } public static JSSourceFile fromInputStream(String fileName, InputStream s) throws IOException { return new JSSourceFile(SourceFile.fromInputStream(fileName, s)); } public static JSSourceFile fromGenerator(String

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>codingConvention = compiler.getCodingConvention(); this.types = Lists.newArrayList(); } public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.CALL: String className = findRequire ? codingConvention.extractClassNameIfRequire(n, parent) : codingConvention.extractClassNameIfProvide(n, parent); if (className != null) { types.add(className); } break; } } } /** * Gets the source line for the indicated line number. * * @param lineNumber the line number, 1 being the first line of the file. * @return The line indicated. Does not include the newline at the end * of the file. Returns {@code null} if it does not exist, * or if there was an IO exception. */ public String getLine(int lineNumber) { return getSourceFile().getLine(lineNumber); } /** * Get a region around the indicated line number. The exact definition of a * region is implementation specific, but it must contain the line indicated * by the line number. A region must not start or end by a carriage return. * * @param lineNumber the line number, 1 being the first line of the file. * @return The line indicated. Returns {@code null} if it does not exist, * or if there was an IO exception. */ public Region getRegion(int lineNumber) { return getSourceFile().getRegion(lineNumber); } public String getCode() throws IOException { return getSourceFile().getCode(); } /** Returns the module to which the input belongs. */ public JSModule getModule() { return module; } /** Sets the module to which the input belongs. */ public void setModule(JSModule module) { // An input may only belong to one module. Preconditions.checkArgument( module == null || this.module == null || this.module == module); this.module = module; } public boolean isExtern() { return isExtern; } }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> Default clock that calls through to the system clock. Can be overridden * in unit tests. */ static InternalClock clock = new InternalClock() { public long currentTimeMillis() { return System.currentTimeMillis(); } }; /** * Create and start a tracer. * Both type and comment may be null. See class comment for usage. * * @param type The type for totalling * @param comment Comment about this tracer */ Tracer(@Nullable String type, @Nullable String comment) { this.type = type; this.comment = comment == null ? "" : comment; startTimeMs = clock.currentTimeMillis(); startThread = Thread.currentThread(); if (!extraTracingStatistics.isEmpty()) { int size = extraTracingStatistics.size(); extraTracingValues = new long[size]; int i = 0; for (TracingStatistic tracingStatistic : extraTracingStatistics) { extraTracingValues[i] = tracingStatistic.start(startThread); i++; } } ThreadTrace trace = getThreadTrace(); // Do nothing if the current thread trace wasn't initialized. if (!trace.isInitialized()) { return; } // Check if we are creating too many Tracers. if (trace.events.size() >= MAX_TRACE_SIZE) { logger.log(Level.WARNING, "Giant thread trace. Too many Tracers created. " + "Clearing to avoid memory leak.", new Throwable(trace.toString())); trace.truncateEvents(); } // Check if we forgot to close the Tracers. if (trace.outstandingEvents.size() >= MAX_TRACE_SIZE) { logger.log(Level.WARNING, "Too many outstanding Tracers. Tracer.stop() is missing " + "or Tracer.stop() is not wrapped in a " + "try/finally block. " + "Clearing to avoid memory leak.", new Throwable(trace.toString())); trace.truncateOutstandingEvents(); } trace.startEvent(this); } /** * Create a tracer that isn't summed as part of a total * * @param comment Comment about this tracer */ Tracer(String comment) { this(null, comment); } /** *

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> Construct a tracer whose type is based on the short name of the object * @param object Object to use as type name * @param comment A comment * @return new Tracer. */ static Tracer shortName(Object object, String comment) { if (object == null) { return new Tracer(comment); } return new Tracer(object.getClass().getSimpleName(), comment); } /** * Converts 'v' to a string and pads it with up to 16 spaces for * improved alignment. * @param v The value to convert. * @param digits_column_width The desired with of the string. */ private static String longToPaddedString(long v, int digits_column_width) { int digit_width = numDigits(v); StringBuilder sb = new StringBuilder(); appendSpaces(sb, digits_column_width - digit_width); sb.append(v); return sb.toString(); } /** * Gets the number of digits in an integer when printed in base 10. Assumes * a positive integer. * @param n The value. * @return The number of digits in the string. */ private static int numDigits(long n) { int i = 0; do { i++; n = n / 10; } while (n > 0); return i; } /** * Gets a string of spaces of the length specified. * @param sb The string builder to append to. * @param numSpaces The number of spaces in the string. */ @VisibleForTesting static void appendSpaces(StringBuilder sb, int numSpaces) { if (numSpaces > 16) { logger.warning("Tracer.appendSpaces called with large numSpaces"); // Avoid long loop in case some bug in the caller numSpaces = 16; } while (numSpaces >= 5) { sb.append(" "); numSpaces -= 5; } // We know it's less than 5 now switch (numSpaces) { case 1: sb.append(" "); break; case 2: sb.append(" "); break; case 3: sb.append("

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> "); break; case 4: sb.append(" "); break; } } /** * Adds a new tracing statistic to a trace * * @param tracingStatistic to enable a run * @return The index of this statistic (for use with stat.extraInfo()), or * -1 if the statistic is not enabled. */ static int addTracingStatistic(TracingStatistic tracingStatistic) { // Check to see if we can enable the tracing statistic before actually // adding it. if (tracingStatistic.enable()) { // No synchronization needed, since this is a copy-on-write array. extraTracingStatistics.add(tracingStatistic); // 99.9% of the time, this will be O(1) and return extraTracingStatistics.length - 1 return extraTracingStatistics.lastIndexOf(tracingStatistic); } else { return -1; } } /** * For testing purposes only. These removes all current tracers. Severe errors can occur * if there are any active tracers going on when this is called. * * The test suite uses this to remove any tracers that it has added. */ @VisibleForTesting static void clearTracingStatisticsTestingOnly() { extraTracingStatistics.clear(); } /** * Stop the trace. * This may only be done once and must be done from the same thread * that started it. * @param silence_threshold Traces for time less than silence_threshold * ms will be left out of the trace report. A value of -1 indicates * that the current ThreadTrace silence_threshold should be used. * @return The time that this trace actually ran */ long stop(int silence_threshold) { Preconditions.checkState(Thread.currentThread() == startThread); ThreadTrace trace = getThreadTrace(); // Do nothing if the thread trace was not initialized. if (!trace.isInitialized()) { return 0; } stopTimeMs = clock.currentTimeMillis(); if (extraTracingValues != null) { // We use extraTracingValues.length rather than extraTracingStatistics.size() because // a new statistic may have been added for (int i = 0; i < extraTracingValues.length; i++) {

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> long value = extraTracingStatistics.get(i).stop(startThread); extraTracingValues[i] = value - extraTracingValues[i]; } } // Do nothing if the thread trace was not initialized. if (!trace.isInitialized()) { return 0; } trace.endEvent(this, silence_threshold); return stopTimeMs - startTimeMs; } /** Stop the trace using the default silence_threshold * * @return The time that this trace actually ran. */ long stop() { return stop(-1); } @Override public String toString() { if (type == null) { return comment; } else { return "[" + type + "] " + comment; } } static void setDefaultSilenceThreshold(int threshold) { getThreadTrace().defaultSilenceThreshold = threshold; } /** * Initialize the trace associated with the current thread by clearing * out any existing trace. There shouldn't be a trace so if one is * found we log it as an error. */ static void initCurrentThreadTrace() { ThreadTrace events = getThreadTrace(); if (!events.isEmpty()) { logger.log(Level.WARNING, "Non-empty timer log:\n" + events, new Throwable()); clearThreadTrace(); // Grab a new thread trace if we find a previous non-empty ThreadTrace. events = getThreadTrace(); } // Mark the thread trace as initialized. events.init(); } static void initCurrentThreadTrace(int default_silence_threshold) { initCurrentThreadTrace(); setDefaultSilenceThreshold(default_silence_threshold); } /** * Returns a timer report similar to the one described in the class comment. * * @return The timer report as a string */ static String getCurrentThreadTraceReport() { return getThreadTrace().toString(); } /** * Logs a timer report similar to the one described in the class comment. */ static void logCurrentThreadTrace() { ThreadTrace trace = getThreadTrace(); // New threads must call Tracer.initCurrentThreadTrace() before Tracer // statistics are gathered. This is a recent change (Jun 2007) that // prevents spurious Third

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>0:06:11.566", "11.566") */ private static String formatTime(long time) { int sec = (int) ((time / 1000) % 60); int ms = (int) (time % 1000); return String.format("%02d.%03d", sec, ms); } /** An event is created every time a Tracer is created or stopped */ private static final class Event { boolean isStart; // else is_stop Tracer tracer; Event(boolean start, Tracer t) { isStart = start; tracer = t; } long eventTime() { return isStart ? tracer.startTimeMs : tracer.stopTimeMs; } /** * Converts the event to a formatted string. * @param prevEventTime The time of the previous event which appears at * the left most part of the trace line. * @param indent The indentation to put before the tracer to show the * hieararchy. * @param digitsColWidth How many characters the digits should use. * @return The formatted string. */ String toString(long prevEventTime, String indent, int digitsColWidth) { StringBuilder sb = new StringBuilder(120); if (prevEventTime == -1) { appendSpaces(sb, digitsColWidth); } else { sb.append(longToPaddedString(eventTime() - prevEventTime, digitsColWidth)); } sb.append(' '); sb.append(formatTime(eventTime())); if (isStart) { sb.append(" Start "); appendSpaces(sb, digitsColWidth); sb.append(" "); } else { sb.append(" Done "); long delta = tracer.stopTimeMs - tracer.startTimeMs; sb.append(longToPaddedString(delta, digitsColWidth)); sb.append(" ms "); if (tracer.extraTracingValues != null) { for (int i = 0; i < tracer.extraTracingValues.length; i++) { delta = tracer.extraTracingValues[i]; sb.append(String.format("%4d", delta)); sb.append(extraTracing

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>Statistics.get(i).getUnits()); sb.append("; "); } } } sb.append(indent); sb.append(tracer.toString()); return sb.toString(); } } /** Stores a thread's Trace */ static final class ThreadTrace { /** Events taking less than this number of milliseconds are not reported. */ int defaultSilenceThreshold; // non-final /** The Events corresponding to each startEvent/stopEvent */ final ArrayList<Event> events = new ArrayList<Event>(); /** Tracers that have not had their .stop() called */ final HashSet<Tracer> outstandingEvents = new HashSet<Tracer>(); /** Map from type to Stat object */ final Map<String, Stat> stats = new HashMap<String, Stat>(); /** * True if {@code outstandingEvents} has been cleared because we exceeded * the max trace limit. */ boolean isOutstandingEventsTruncated = false; /** * True if {@code events} has been cleared because we exceeded the max * trace limit. */ boolean isEventsTruncated = false; /** * Set to true if {@link Tracer#initCurrentThreadTrace()} was called by * the current thread. */ boolean isInitialized = false; /** * Whether pretty printing is enabled for the trace. */ boolean prettyPrint = false; /** Initialize the trace. */ void init() { isInitialized = true; } /** Is initialized? */ boolean isInitialized() { return isInitialized; } /** * Called by the constructor {@link Tracer#Tracer(String, String)} to create * a start event. */ void startEvent(Tracer t) { events.add(new Event(true, t)); boolean notAlreadyOutstanding = outstandingEvents.add(t); Preconditions.checkState(notAlreadyOutstanding); } /** * Called by {@link Tracer#stop()} to create a stop event. */ void endEvent(Tracer t, int silenceThreshold) { boolean wasOutstanding = outstandingEvents.remove(t); if (!wasOutstanding) { if (isOutstandingEventsTruncated) { // The events stack overflowed and was truncated, so just log a // warning. Otherwise, we get an exception which is extremely

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> // confusing. logger.log(Level.WARNING, "event not found, probably because the event stack " + "overflowed and was truncated", new Throwable()); } else { // throw an exception if the event was not found and the events stack // is pristine throw new IllegalStateException(); } } long elapsed = t.stopTimeMs - t.startTimeMs; if (silenceThreshold == -1) { // use default silenceThreshold = defaultSilenceThreshold; } if (elapsed < silenceThreshold) { // If this one is silent then we need to remove the start Event boolean removed = false; for (int i = 0; i < events.size(); i++) { Event e = events.get(i); if (e.tracer == t) { Preconditions.checkState(e.isStart); events.remove(i); removed = true; break; } } // Only assert if we didn't find the original and the events // weren't truncated. Preconditions.checkState(removed || isEventsTruncated); } else { events.add(new Event(false, t)); } if (t.type != null) { Stat stat = stats.get(t.type); if (stat == null) { stat = new Stat(); if (!extraTracingStatistics.isEmpty()) { stat.extraInfo = new int[extraTracingStatistics.size()]; } stats.put(t.type, stat); } stat.count++; if (typeToCountMap != null) { typeToCountMap.incrementBy(t.type, 1); } stat.clockTime += elapsed; if (typeToTimeMap != null) { typeToTimeMap.incrementBy(t.type, elapsed); } if (stat.extraInfo != null && t.extraTracingValues != null) { int overlapLength = Math.min(stat.extraInfo.length, t.extraTracingValues.length); for (int i = 0; i < overlapLength; i++) { stat.extraInfo[i] += t.extraTracingValues[i]; AtomicTracerStatMap map = extraTracingStatistics.get(i).getTracingStat(); if (map !=

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> null) { map.incrementBy(t.type, t.extraTracingValues[i]); } } } if (elapsed < silenceThreshold) { stat.silent++; if (typeToSilentMap != null) { typeToSilentMap.incrementBy(t.type, 1); } } } } boolean isEmpty() { return events.size() == 0 && outstandingEvents.size() == 0; } void truncateOutstandingEvents() { isOutstandingEventsTruncated = true; outstandingEvents.clear(); } void truncateEvents() { isEventsTruncated = true; events.clear(); } /** Produces the lovely Trace seen in the class comments */ // Nullness checker does not understand that prettyPrint => indent != null @SuppressWarnings("nullness") @Override public String toString() { int numDigits = getMaxDigits(); StringBuilder sb = new StringBuilder(); long etime = -1; LinkedList<String> indent = prettyPrint ? new LinkedList<String>() : null; for (Event e : events) { if (prettyPrint && !e.isStart && !indent.isEmpty()) { indent.pop(); } sb.append(" "); if (prettyPrint) { sb.append(e.toString(etime, Joiner.on("").join(indent), numDigits)); } else { sb.append(e.toString(etime, "", 4)); } etime = e.eventTime(); sb.append('\n'); if (prettyPrint && e.isStart) { indent.push("| "); } } if (outstandingEvents.size() != 0) { long now = clock.currentTimeMillis(); sb.append(" Unstopped timers:\n"); for (Tracer t : outstandingEvents) { sb.append(" "). append(t). append(" ("). append(now - t.startTimeMs). append(" ms, started at "). append(formatTime(t.startTimeMs)). append(")\n"); } } for (String key : stats.keySet()) { Stat stat = stats.get(key); if (stat.count > 1) { sb.append(" TOTAL "). append(

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>key). append(" "). append(stat.count). append(" ("). append(stat.clockTime). append(" ms"); if (stat.extraInfo != null) { for (int i = 0; i < stat.extraInfo.length; i++) { sb.append("; "); sb.append(stat.extraInfo[i]). append(' '). append(extraTracingStatistics.get(i).getUnits()); } } sb.append(")\n"); } } return sb.toString(); } /** * Gets the maximum number of digits that can appear in the tracer output * in the gaps between tracers or the duration of a tracer. This is used * by the pretty printing case so that all of the tracers are aligned. */ private int getMaxDigits() { long etime = -1; long max_time = 0; for (Event e : events) { if (etime != -1) { long time = e.eventTime() - etime; max_time = Math.max(max_time, time); } if (!e.isStart) { long time = e.tracer.stopTimeMs - e.tracer.startTimeMs; max_time = Math.max(max_time, time); } etime = e.eventTime(); } // Minimum is 3 to preserve an indent even when max is small. return Math.max(3, numDigits(max_time)); } } /** Holds the ThreadTrace for each thread. */ private static ThreadLocal<ThreadTrace> traces = new ThreadLocal<ThreadTrace>(); /** * Get the ThreadTrace for the current thread, creating one if necessary. */ static ThreadTrace getThreadTrace() { ThreadTrace t = traces.get(); if (t == null) { t = new ThreadTrace(); t.prettyPrint = defaultPrettyPrint; traces.set(t); } return t; } /** Remove any ThreadTrace associated with the current thread */ static void clearThreadTrace() { traces.set(null); } /** * A TracingStatistic allows the program to add additional optional statistics to the trace * output. * * The

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> path through // the code identical to how it's been for years. this.outputCharsetEncoder = null; } else { this.outputCharsetEncoder = outputCharset.newEncoder(); } } CodeGenerator(CodeConsumer consumer, Charset outputCharset) { this(consumer, outputCharset, true); } CodeGenerator(CodeConsumer consumer) { this(consumer, null, false); } void add(String str) { cc.add(str); } private void addIdentifier(String identifier) { cc.addIdentifier(identifierEscape(identifier)); } void add(Node n) { add(n, Context.OTHER); } void add(Node n, Context context) { if (!cc.continueProcessing()) { return; } int type = n.getType(); String opstr = NodeUtil.opToStr(type); int childCount = n.getChildCount(); Node first = n.getFirstChild(); Node last = n.getLastChild(); // Handle all binary operators if (opstr != null && first != last) { Preconditions.checkState(childCount == 2); int p = NodeUtil.precedence(type); addLeftExpr(first, p, context); cc.addOp(opstr, true); // For right-hand-side of operations, only pass context if it's // the IN_FOR_INIT_CLAUSE one. Context rhsContext = getContextForNoInOperator(context); // Handle associativity. // e.g. if the parse tree is a * (b * c), // we can simply generate a * b * c. if (last.getType() == type && NodeUtil.isAssociative(type)) { addExpr(last, p, rhsContext); } else if (NodeUtil.isAssignmentOp(n) && NodeUtil.isAssignmentOp(last)) { // Assignments are the only right-associative binary operators addExpr(last, p, rhsContext); } else { addExpr(last, p + 1, rhsContext); } return; } cc.startSourceMapping(n); switch (type) { case Token.TRY: { Preconditions.checkState(first.getNext().getType() ==

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> Token.BLOCK && first.getNext().getChildCount() <= 1); Preconditions.checkState(childCount >= 2 && childCount <= 3); add("try"); add(first, Context.PRESERVE_BLOCK); // second child contains the catch block, or nothing if there // isn't a catch block Node catchblock = first.getNext().getFirstChild(); if (catchblock != null) { add(catchblock); } if (childCount == 3) { add("finally"); add(last, Context.PRESERVE_BLOCK); } break; } case Token.CATCH: Preconditions.checkState(childCount == 3); if (first.getNext().getType() != Token.EMPTY) { throw new Error("Catch conditions not suppored because I think" + " that it may be a netscape only feature."); } add("catch("); add(first); add(")"); add(last, Context.PRESERVE_BLOCK); break; case Token.THROW: Preconditions.checkState(childCount == 1); add("throw"); add(first); // Must have a ';' after a throw statement, otherwise safari can't // parse this. cc.endStatement(true); break; case Token.RETURN: add("return"); if (childCount == 1) { add(first); } else { Preconditions.checkState(childCount == 0); } cc.endStatement(); break; case Token.VAR: if (first != null) { add("var "); addList(first, false, getContextForNoInOperator(context)); } break; case Token.NAME: if (first == null || first.getType() == Token.EMPTY) { addIdentifier(n.getString()); } else { Preconditions.checkState(childCount == 1); addIdentifier(n.getString()); cc.addOp("=", true); if (first.getType() == Token.COMMA) { addExpr(first, NodeUtil.precedence(Token.ASSIGN)); } else { // Add expression, consider nearby code at lowest level of // precedence. addExpr(first, 0, getContextForNoInOperator

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>(context)); } } break; case Token.ARRAYLIT: add("["); addList(first, (int[]) n.getProp(Node.SKIP_INDEXES_PROP)); add("]"); break; case Token.LP: add("("); addList(first); add(")"); break; case Token.COMMA: addList(first, false, context); break; case Token.NUMBER: Preconditions.checkState(childCount == 0); cc.addNumber(n.getDouble()); break; case Token.TYPEOF: case Token.VOID: case Token.NOT: case Token.BITNOT: case Token.POS: case Token.NEG: { // All of these unary operators are right-associative Preconditions.checkState(childCount == 1); cc.addOp(NodeUtil.opToStrNoFail(type), false); addExpr(first, NodeUtil.precedence(type)); break; } case Token.HOOK: { Preconditions.checkState(childCount == 3); int p = NodeUtil.precedence(type); addLeftExpr(first, p + 1, context); cc.addOp("?", true); addExpr(first.getNext(), p); cc.addOp(":", true); addExpr(last, p); break; } case Token.REGEXP: if (first.getType() != Token.STRING || last.getType() != Token.STRING) { throw new Error("Expected children to be strings"); } String regexp = regexpEscape(first.getString(), outputCharsetEncoder); // I only use one .add because whitespace matters if (childCount == 2) { add(regexp + last.getString()); } else { Preconditions.checkState(childCount == 1); add(regexp); } break; case Token.GET_REF: add(first); break; case Token.REF_SPECIAL: Preconditions.checkState(childCount == 1); add(first); add("."); add((String) n.getProp(Node.NAME_PROP)); break; case Token.FUNCTION: Preconditions.checkState(childCount == 3);

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> boolean funcNeedsParens = (context == Context.START_OF_EXPR); if (funcNeedsParens) { add("("); } add("function"); add(first); add(first.getNext()); add(last, Context.PRESERVE_BLOCK); cc.endFunction(context == Context.STATEMENT); if (funcNeedsParens) { add(")"); } break; case Token.SCRIPT: case Token.BLOCK: { boolean stripBlock = n.isSyntheticBlock() || ((context != Context.PRESERVE_BLOCK) && (n.getChildCount() < 2)); if (!stripBlock) { cc.beginBlock(); } for (Node c = first; c != null; c = c.getNext()) { add(c, Context.STATEMENT); // VAR doesn't include ';' since it gets used in expressions if (c.getType() == Token.VAR) { cc.endStatement(); } if (c.getType() == Token.FUNCTION) { cc.maybeLineBreak(); } // Prefer to break lines in between top-level statements // because top level statements are more homogeneous. if (type == Token.SCRIPT) { cc.notePreferredLineBreak(); } } if (!stripBlock) { cc.endBlock(context == Context.STATEMENT); } break; } case Token.FOR: if (childCount == 4) { add("for("); if (first.getType() == Token.VAR) { add(first, Context.IN_FOR_INIT_CLAUSE); } else { addExpr(first, 0, Context.IN_FOR_INIT_CLAUSE); } add(";"); add(first.getNext()); add(";"); add(first.getNext().getNext()); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); } else { Preconditions.checkState(childCount == 3); add("for("); add(first); add("in"); add(first.getNext()); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); } break

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>; case Token.DO: Preconditions.checkState(childCount == 2); add("do"); addNonEmptyExpression(first, Context.OTHER, false); add("while("); add(last); add(")"); cc.endStatement(); break; case Token.WHILE: Preconditions.checkState(childCount == 2); add("while("); add(first); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); break; case Token.EMPTY: Preconditions.checkState(childCount == 0); break; case Token.GETPROP: { Preconditions.checkState(childCount == 2); Preconditions.checkState(last.getType() == Token.STRING); boolean needsParens = (first.getType() == Token.NUMBER); if (needsParens) { add("("); } addLeftExpr(first, NodeUtil.precedence(type), context); if (needsParens) { add(")"); } add("."); addIdentifier(last.getString()); break; } case Token.GETELEM: Preconditions.checkState(childCount == 2); addLeftExpr(first, NodeUtil.precedence(type), context); add("["); add(first.getNext()); add("]"); break; case Token.WITH: Preconditions.checkState(childCount == 2); add("with("); add(first); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); break; case Token.INC: case Token.DEC: { Preconditions.checkState(childCount == 1); String o = type == Token.INC ? "++" : "--"; int postProp = n.getIntProp(Node.INCRDECR_PROP, 0); // A non-zero post-prop value indicates a post inc/dec, default of zero // is a pre-inc/dec. if (postProp != 0) { addLeftExpr(first, NodeUtil.precedence(type), context); cc.addOp(o, false); } else { cc.addOp(o, false);

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> add(first); } break; } case Token.CALL: // If the left hand side of the call is a direct reference to eval, // then it must have a DIRECT_EVAL annotation. If it does not, then // that means it was originally an indirect call to eval, and that // indirectness must be preserved. if (first.getType() == Token.NAME && "eval".equals(first.getString()) && !first.getBooleanProp(Node.DIRECT_EVAL)) { add("(0,eval)"); } else { addLeftExpr(first, NodeUtil.precedence(type), context); } add("("); addList(first.getNext()); add(")"); break; case Token.IF: boolean hasElse = childCount == 3; boolean ambiguousElseClause = context == Context.BEFORE_DANGLING_ELSE && !hasElse; if (ambiguousElseClause) { cc.beginBlock(); } add("if("); add(first); add(")"); if (hasElse) { addNonEmptyExpression( first.getNext(), Context.BEFORE_DANGLING_ELSE, false); add("else"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); } else { addNonEmptyExpression(first.getNext(), Context.OTHER, false); Preconditions.checkState(childCount == 2); } if (ambiguousElseClause) { cc.endBlock(); } break; case Token.NULL: case Token.THIS: case Token.FALSE: case Token.TRUE: Preconditions.checkState(childCount == 0); add(Node.tokenToName(type)); break; case Token.CONTINUE: Preconditions.checkState(childCount <= 1); add("continue"); if (childCount == 1) { add(" "); add(first); } cc.endStatement(); break; case Token.DEBUGGER: Preconditions.checkState(childCount == 0); add("debugger"); cc.endStatement(); break; case Token.BREAK: Preconditions.checkState(childCount <= 1); add("break"); if (childCount

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> == 1) { add(" "); add(first); } cc.endStatement(); break; case Token.EXPR_VOID: case Token.EXPR_RESULT: if (type == Token.EXPR_VOID && validation) { throw new Error("Unexpected EXPR_VOID. Should be EXPR_RESULT."); } Preconditions.checkState(childCount == 1); add(first, Context.START_OF_EXPR); cc.endStatement(); break; case Token.NEW: add("new "); int precedence = NodeUtil.precedence(type); // If the first child contains a CALL, then claim higher precedence // to force parens. Otherwise, when parsed, NEW will bind to the // first viable parens if (NodeUtil.containsCall(first)) { precedence = NodeUtil.precedence(first.getType()) + 1; } addExpr(first, precedence); // '()' is optional when no arguments are present Node next = first.getNext(); if (next != null) { add("("); addList(next); add(")"); } break; case Token.STRING: Preconditions.checkState(childCount == 0); add(jsString(n.getString(), outputCharsetEncoder)); break; case Token.DELPROP: Preconditions.checkState(childCount == 1); add("delete "); add(first); break; case Token.OBJECTLIT: { Preconditions.checkState(childCount % 2 == 0); boolean needsParens = (context == Context.START_OF_EXPR); if (needsParens) { add("("); } add("{"); for (Node c = first; c != null; c = c.getNext().getNext()) { if (c != first) { cc.listSeparator(); } // Object literal property names don't have to be quoted if they are // not JavaScript keywords if (c.getType() == Token.STRING && !TokenStream.isKeyword(c.getString()) && TokenStream.isJSIdentifier(c.getString()) && // do not encode literally any non-literal characters that were // unicode escaped. NodeUtil.isLatin(c.getString()))

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> { add(c.getString()); } else { addExpr(c, 1); } add(":"); addExpr(c.getNext(), 1); } add("}"); if (needsParens) { add(")"); } break; } case Token.SWITCH: add("switch("); add(first); add(")"); cc.beginBlock(); addAllSiblings(first.getNext()); cc.endBlock(context == Context.STATEMENT); break; case Token.CASE: Preconditions.checkState(childCount == 2); add("case "); add(first); addCaseBody(last); break; case Token.DEFAULT: Preconditions.checkState(childCount == 1); add("default"); addCaseBody(first); break; case Token.LABEL: Preconditions.checkState(childCount == 2); add(first); add(":"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), true); break; // This node is auto generated in anonymous functions and should just get // ignored for our purposes. case Token.SETNAME: break; default: throw new Error("Unknown type " + type + "\n" + n.toStringTree()); } cc.endSourceMapping(n); } /** * Adds a block or expression, substituting a VOID with an empty statement. * This is used for "for (...);" and "if (...);" type statements. * * @param n The node to print. * @param context The context to determine how the node should be printed. */ private void addNonEmptyExpression( Node n, Context context, boolean allowNonBlockChild) { Node nodeToProcess = n; if (!allowNonBlockChild && n.getType() != Token.BLOCK) { if (validation) { throw new Error("Missing BLOCK child."); } } // Strip unneeded blocks, that is blocks with <2 children unless // the CodePrinter specifically wants to keep them. if (n.getType() == Token.BLOCK ) { int count = getNonEmptyChildCount(n); if (count == 0) { cc.endStatement(true); return;

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> } if (count == 1) { // Hack around a couple of browser bugs: // Safari needs a block around function declarations. // IE6/7 needs a block around DOs. Node firstAndOnlyChild = getFirstNonEmptyChild(n); boolean alwaysWrapInBlock = cc.shouldPreserveExtraBlocks(); if (alwaysWrapInBlock || firstAndOnlyChild.getType() == Token.FUNCTION || firstAndOnlyChild.getType() == Token.DO) { cc.beginBlock(); add(firstAndOnlyChild, Context.STATEMENT); cc.maybeLineBreak(); cc.endBlock(context == Context.STATEMENT); return; } else { // Continue with the only child. nodeToProcess = firstAndOnlyChild; } } } if (nodeToProcess.getType() == Token.EMPTY) { cc.endStatement(true); } else { add(nodeToProcess, context); // VAR doesn't include ';' since it gets used in expressions - so any // VAR in a statement context needs a call to endStatement() here. if (nodeToProcess.getType() == Token.VAR) { cc.endStatement(); } } } /** * Adds a node at the left-hand side of an expression. Unlike * {@link #addExpr(Node,int)}, this preserves information about the context. * * The left side of an expression is special because in the JavaScript * grammar, certain tokens may be parsed differently when they are at * the beginning of a statement. For example, "{}" is parsed as a block, * but "{'x': 'y'}" is parsed as an object literal. */ void addLeftExpr(Node n, int minPrecedence, Context context) { addExpr(n, minPrecedence, context); } void addExpr(Node n, int minPrecedence) { addExpr(n, minPrecedence, Context.OTHER); } private void addExpr(Node n, int minPrecedence, Context context) { if ((NodeUtil.precedence(n.getType()) < minPrecedence) || ((context == Context.IN_FOR_INIT_CLAUSE) && (n.getType() == Token.IN))

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>){ add("("); add(n, clearContextForNoInOperator(context)); add(")"); } else { add(n, context); } } void addList(Node firstInList) { addList(firstInList, true, Context.OTHER); } void addList(Node firstInList, boolean isArrayOrFunctionArgument) { addList(firstInList, isArrayOrFunctionArgument, Context.OTHER); } void addList(Node firstInList, boolean isArrayOrFunctionArgument, Context lhsContext) { for (Node n = firstInList; n != null; n = n.getNext()) { boolean isFirst = n == firstInList; if (isFirst) { addLeftExpr(n, isArrayOrFunctionArgument ? 1 : 0, lhsContext); } else { cc.listSeparator(); addExpr(n, isArrayOrFunctionArgument ? 1 : 0); } } } /** * This function adds a comma-separated list as is specified by an ARRAYLIT * node with the associated skipIndexes array. This is a space optimization * since we avoid creating a whole Node object for each empty array literal * slot. * @param firstInList The first in the node list (chained through the next * property). * @param skipIndexes If not null, then the array of skipped entries in the * array. */ void addList(Node firstInList, int[] skipIndexes) { int nextSlot = 0; int nextSkipSlot = 0; for (Node n = firstInList; n != null; n = n.getNext()) { while (skipIndexes != null && nextSkipSlot < skipIndexes.length) { if (nextSlot == skipIndexes[nextSkipSlot]) { cc.listSeparator(); nextSlot++; nextSkipSlot++; } else { break; } } if (n != firstInList) { cc.listSeparator(); } addExpr(n, 1); nextSlot++; } } void addCaseBody(Node caseBody) { cc.beginCaseBody(); add(caseBody); cc.endCaseBody(); } void addAllSiblings(Node n) {

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> for (Node c = n; c != null; c = c.getNext()) { add(c); } } /** Outputs a js string, using the optimal (single/double) quote character */ static String jsString(String s, CharsetEncoder outputCharsetEncoder) { int singleq = 0, doubleq = 0; // could count the quotes and pick the optimal quote character for (int i = 0; i < s.length(); i++) { switch (s.charAt(i)) { case '"': doubleq++; break; case '\'': singleq++; break; } } String doublequote, singlequote; char quote; if (singleq < doubleq) { // more double quotes so escape the single quotes quote = '\''; doublequote = "\""; singlequote = "\\\'"; } else { // more single quotes so escape the doubles quote = '\"'; doublequote = "\\\""; singlequote = "\'"; } return strEscape(s, quote, doublequote, singlequote, "\\\\", outputCharsetEncoder); } /** Escapes regular expression */ static String regexpEscape(String s, CharsetEncoder outputCharsetEncoder) { return strEscape(s, '/', "\"", "'", "\\", outputCharsetEncoder); } /** * Escapes the given string to a double quoted (") JavaScript/JSON string */ static String escapeToDoubleQuotedJsString(String s) { return strEscape(s, '"', "\\\"", "\'", "\\\\", null); } /* If the user doesn't want to specify an output charset encoder, assume they want Latin/ASCII characters only. */ static String regexpEscape(String s) { return regexpEscape(s, null); } /** Helper to escape javascript string as well as regular expression */ static String strEscape(String s, char quote, String doublequoteEscape, String singlequoteEscape, String backslashEscape, CharsetEncoder outputCharsetEncoder) { StringBuilder sb = new StringBuilder(); sb.append(quote); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); switch (c) { case '\n': sb.append("\\n"); break; case

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> '\r': sb.append("\\r"); break; case '\t': sb.append("\\t"); break; case '\\': sb.append(backslashEscape); break; case '\"': sb.append(doublequoteEscape); break; case '\'': sb.append(singlequoteEscape); break; case '>': // Break --> into --\> or ]]> into ]]\> if (i >= 2 && ((s.charAt(i - 1) == '-' && s.charAt(i - 2) == '-') || (s.charAt(i - 1) == ']' && s.charAt(i - 2) == ']'))) { sb.append("\\>"); } else { sb.append(c); } break; case '<': // Break </script into <\/script final String END_SCRIPT = "/script"; if (s.regionMatches(true, i + 1, END_SCRIPT, 0, END_SCRIPT.length())) { sb.append("<\\"); } else { sb.append(c); } break; default: // If we're given an outputCharsetEncoder, then check if the // character can be represented in this character set. if (outputCharsetEncoder != null) { if (outputCharsetEncoder.canEncode(c)) { sb.append(c); } else { // Unicode-escape the character. appendHexJavaScriptRepresentation(sb, c); } } else { // No charsetEncoder provided - pass straight latin characters // through, and escape the rest. Doing the explicit character // check is measurably faster than using the CharsetEncoder. if (c > 0x1f && c <= 0x7f) { sb.append(c); } else { // Other characters can be misinterpreted by some js parsers, // or perhaps mangled by proxies along the way, // so we play it safe and unicode escape them. appendHexJavaScriptRepresentation(sb, c); } } } } sb.append(quote); return sb.toString(); } static String identifierEscape(String s) { // First check if escaping is needed at all -- in most cases it isn't. if (NodeUtil

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>.isLatin(s)) { return s; } // Now going through the string to escape non-latin characters if needed. StringBuilder sb = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); // Identifiers should always go to Latin1/ ASCII characters because // different browser's rules for valid identifier characters are // crazy. if (c > 0x1F && c < 0x7F) { sb.append(c); } else { appendHexJavaScriptRepresentation(sb, c); } } return sb.toString(); } /** Gets the number of children of this node that are non empty. */ private static int getNonEmptyChildCount(Node n) { int i = 0; for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (c.getType() != Token.EMPTY) { i++; } } return i; } /** Gets the first non-empty child of the given node. */ private static Node getFirstNonEmptyChild(Node n) { for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (c.getType() != Token.EMPTY) { return c; } } return null; } // Information on the current context. Used for disambiguating special cases. // For example, a "{" could indicate the start of an object literal or a // block, depending on the current context. enum Context { STATEMENT, BEFORE_DANGLING_ELSE, // a hack to resolve the else-clause ambiguity START_OF_EXPR, PRESERVE_BLOCK, // Are we inside the init clause of a for loop? If so, the containing // expression can't contain an in operator. Pass this context flag down // until we reach expressions which no longer have the limitation. IN_FOR_INIT_CLAUSE, OTHER } private Context getContextForNonEmptyExpression(Context currentContext) { return currentContext == Context.BEFORE_DANGLING_ELSE ? Context.BEFORE_DANGLING_ELSE : Context.OTHER;

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>and so an assignment // to the property of z would not violate any restrictions on it. for (String property : typeB.properties.keySet()) { if (!typeA.hasProperty(property)) { return false; } JSType propA = typeA.getPropertyType(property); JSType propB = typeB.getPropertyType(property); if (!propA.isUnknownType() && !propB.isUnknownType()) { if (typeA.isPropertyTypeDeclared(property)) { if (!propA.equals(propB)) { return false; } } else { if (!propA.isSubtype(propB)) { return false; } } } } return true; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("{ "); int i = 0; for (String property : properties.keySet()) { if (i > 0) { sb.append(", "); } sb.append(property); sb.append(" : "); sb.append(properties.get(property).toString()); ++i; } sb.append(" }"); return sb.toString(); } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { for (Map.Entry<String, JSType> entry : properties.entrySet()) { JSType type = entry.getValue(); JSType resolvedType = type.resolve(t, scope); if (type != resolvedType) { properties.put(entry.getKey(), resolvedType); } } return super.resolveInternal(t, scope); } }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> (it.hasNext()) { JSType current = it.next(); if (!current.isUnknownType()) { if (alternate.isSubtype(current)) { // Alternate is unnecessary. return this; } else if (current.isSubtype(alternate)) { // Alternate makes current obsolete it.remove(); } } } } alternates.add(alternate); result = null; // invalidate the memoized result } } else { result = null; } return this; } /** * Creates a union. * @return A UnionType if it has two or more alternates, the * only alternate if it has one and otherwise {@code NO_TYPE}. */ JSType build() { if (result == null) { if (isAllType) { result = registry.getNativeType(ALL_TYPE); } else if (isNativeUnknownType) { if (areAllUnknownsChecked) { result = registry.getNativeType(CHECKED_UNKNOWN_TYPE); } else { result = registry.getNativeType(UNKNOWN_TYPE); } } else { Set<JSType> alternateSet = Sets.newUnmodifiableHashSet(alternates); int size = alternateSet.size(); if (size > MAX_UNION_SIZE) { result = registry.getNativeType(UNKNOWN_TYPE); } else { if (size > 1) { result = new UnionType(registry, alternateSet); } else if (size == 1) { result = alternates.iterator().next(); } else { result = registry.getNativeType(NO_TYPE); } } } } return result; } }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> the list of objects registered to receive * notification of changes to a bounded property * @see java.beans.PropertyChangeEvent * @see #addPropertyChangeListener(java.beans.PropertyChangeListener) * @param l the listener */ public final void removePropertyChangeListener(PropertyChangeListener l) { if (sealed) onSealedMutation(); propertyListeners = Kit.removeListener(propertyListeners, l); } /** * Notify any registered listeners that a bounded property has changed * @see #addPropertyChangeListener(java.beans.PropertyChangeListener) * @see #removePropertyChangeListener(java.beans.PropertyChangeListener) * @see java.beans.PropertyChangeListener * @see java.beans.PropertyChangeEvent * @param property the bound property * @param oldValue the old value * @param newValue the new value */ final void firePropertyChange(String property, Object oldValue, Object newValue) { Object listeners = propertyListeners; if (listeners != null) { firePropertyChangeImpl(listeners, property, oldValue, newValue); } } private void firePropertyChangeImpl(Object listeners, String property, Object oldValue, Object newValue) { for (int i = 0; ; ++i) { Object l = Kit.getListener(listeners, i); if (l == null) break; if (l instanceof PropertyChangeListener) { PropertyChangeListener pcl = (PropertyChangeListener)l; pcl.propertyChange(new PropertyChangeEvent( this, property, oldValue, newValue)); } } } /** * Report a warning using the error reporter for the current thread. * * @param message the warning message to report * @param sourceName a string describing the source, such as a filename * @param lineno the starting line number * @param lineSource the text of the line (may be null) * @param lineOffset the offset into lineSource where problem was detected * @see com.google.javascript.rhino.ErrorReporter */ public static void reportWarning(String message, String sourceName, int lineno, String lineSource, int lineOffset) { Context cx = Context.getContext(); cx.getErrorReporter().warning(message, sourceName, lineno, lineSource, lineOffset); }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> associated with current Thread"); } return cx; } final boolean isVersionECMA1() { return version == VERSION_DEFAULT || version >= VERSION_1_3; } static String getSourcePositionFromStack(int[] linep) { Context cx = getCurrentContext(); if (cx == null) return null; /** * A bit of a hack, but the only way to get filename and line * number from an enclosing frame. */ CharArrayWriter writer = new CharArrayWriter(); RuntimeException re = new RuntimeException(); re.printStackTrace(new PrintWriter(writer)); String s = writer.toString(); int open = -1; int close = -1; int colon = -1; for (int i=0; i < s.length(); i++) { char c = s.charAt(i); if (c == ':') colon = i; else if (c == '(') open = i; else if (c == ')') close = i; else if (c == '\n' && open != -1 && close != -1 && colon != -1 && open < colon && colon < close) { String fileStr = s.substring(open + 1, colon); if (!fileStr.endsWith(".java")) { String lineStr = s.substring(colon + 1, close); try { linep[0] = Integer.parseInt(lineStr); if (linep[0] < 0) { linep[0] = 0; } return fileStr; } catch (NumberFormatException e) { // fall through } } open = close = colon = -1; } } return null; } public final boolean isGeneratingDebugChanged() { return generatingDebugChanged; } /** * Add a name to the list of names forcing the creation of real * activation objects for functions. * * @param name the name of the object to add to the list */ public void addActivationName(String name) { if (sealed) onSealedMutation(); if (activationNames == null) activationNames = new Hashtable<Object, Object>(5); activationNames.put(name, name); }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> /** * Use closure's implementation. * @return closure's function name for exporting properties. */ @Override public String getExportPropertyFunction() { return "goog.exportProperty"; } /** * Use closure's implementation. * @return closure's function name for exporting symbols. */ @Override public String getExportSymbolFunction() { return "goog.exportSymbol"; } @Override public List<String> identifyTypeDeclarationCall(Node n) { Node callName = n.getFirstChild(); if ("goog.addDependency".equals(callName.getQualifiedName()) && n.getChildCount() >= 3) { Node typeArray = callName.getNext().getNext(); if (typeArray.getType() == Token.ARRAYLIT) { List<String> typeNames = Lists.newArrayList(); for (Node name = typeArray.getFirstChild(); name != null; name = name.getNext()) { if (name.getType() == Token.STRING) { typeNames.add(name.getString()); } } return typeNames; } } return null; } @Override public String identifyTypeDefAssign(Node n) { Node firstChild = n.getFirstChild(); int type = n.getType(); if (type == Token.ASSIGN) { if (TYPEDEF_NAME.equals(n.getLastChild().getQualifiedName())) { return firstChild.getQualifiedName(); } } else if (type == Token.VAR && firstChild.hasChildren()) { if (TYPEDEF_NAME.equals( firstChild.getFirstChild().getQualifiedName())) { return firstChild.getString(); } } return null; } @Override public String getAbstractMethodName() { return "goog.abstractMethod"; } @Override public String getSingletonGetterClassName(Node callNode) { Node callName = callNode.getFirstChild(); if (!"goog.addSingletonGetter".equals(callName.getQualifiedName()) || callName.getChildCount() != 2) { return null; } Node classNode = callName.getNext(); if (!classNode.isQualifiedName()) { return null; } return callName.getNext().getQualifiedName(); } @Override public void applySingletonGetter(

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> int charno) { this(nodeType, children); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node[] children) { this.type = nodeType; parent = null; if (children.length != 0) { this.first = children[0]; this.last = children[children.length - 1]; for (int i = 1; i < children.length; i++) { if (null != children[i - 1].next) { // fail early on loops. implies same node in array twice throw new IllegalArgumentException("duplicate child"); } children[i - 1].next = children[i]; Preconditions.checkArgument(children[i - 1].parent == null); children[i - 1].parent = this; } Preconditions.checkArgument( children[children.length - 1].parent == null); children[children.length - 1].parent = this; if (null != this.last.next) { // fail early on loops. implies same node in array twice throw new IllegalArgumentException("duplicate child"); } } } public static Node newNumber(double number) { return new NumberNode(number); } public static Node newNumber(double number, int lineno, int charno) { return new NumberNode(number, lineno, charno); } public static Node newString(String str) { return new StringNode(Token.STRING, str); } public static Node newString(int type, String str) { return new StringNode(type, str); } public static Node newString(String str, int lineno, int charno) { return new StringNode(Token.STRING, str, lineno, charno); } public static Node newString(int type, String str, int lineno, int charno) { return new StringNode(type, str, lineno, charno); } public int getType() { return type; } public void setType(int type) { this.type = type; } public boolean hasChildren() { return first != null; } public Node getFirstChild() { return first; } public Node getLastChild

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>() { return last; } public Node getNext() { return next; } public Node getChildBefore(Node child) { if (child == first) return null; Node n = first; while (n.next != child) { n = n.next; if (n == null) throw new RuntimeException("node is not a child"); } return n; } public Node getChildAtIndex(int i) { Node n = first; while (i > 0) { n = n.next; i--; } return n; } public Node getLastSibling() { Node n = this; while (n.next != null) { n = n.next; } return n; } public void addChildToFront(Node child) { Preconditions.checkArgument(child.parent == null); Preconditions.checkArgument(child.next == null); child.parent = this; child.next = first; first = child; if (last == null) { last = child; } } public void addChildToBack(Node child) { Preconditions.checkArgument(child.parent == null); Preconditions.checkArgument(child.next == null); child.parent = this; child.next = null; if (last == null) { first = last = child; return; } last.next = child; last = child; } public void addChildrenToFront(Node children) { for (Node child = children; child != null; child = child.next) { Preconditions.checkArgument(child.parent == null); child.parent = this; } Node lastSib = children.getLastSibling(); lastSib.next = first; first = children; if (last == null) { last = lastSib; } } public void addChildrenToBack(Node children) { for (Node child = children; child != null; child = child.next) { // Hmmm... IRFactory doesn't remove before calling this. Preconditions.checkArgument(child.parent == null); child.parent = this; } if (last != null) { last.next = children; }

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>(sof.getEncodedSourceEnd() - sof.getEncodedSourceStart()); sb.append("] [base line: "); sb.append(sof.getBaseLineno()); sb.append("] [end line: "); sb.append(sof.getEndLineno()); sb.append(']'); } } else if (type == Token.NUMBER) { sb.append(' '); sb.append(getDouble()); } if (printSource) { int lineno = getLineno(); if (lineno != -1) { sb.append(' '); sb.append(lineno); } } if (printAnnotations) { int[] keys = getSortedPropTypes(); for (int i = 0; i < keys.length; i++) { int type = keys[i]; PropListItem x = lookupProperty(type); sb.append(" ["); sb.append(propToString(type)); sb.append(": "); String value; switch (type) { case TARGETBLOCK_PROP : // can't add this as it recurses value = "target block property"; break; case LOCAL_BLOCK_PROP : // can't add this as it is dull value = "last local block"; break; case ISNUMBER_PROP: switch (x.intValue) { case BOTH: value = "both"; break; case RIGHT: value = "right"; break; case LEFT: value = "left"; break; default: throw Kit.codeBug(); } break; case SPECIALCALL_PROP: switch (x.intValue) { case SPECIALCALL_EVAL: value = "eval"; break; case SPECIALCALL_WITH: value = "with"; break; default: // NON_SPECIALCALL should not be stored throw Kit.codeBug(); } break; default : Object obj = x.objectValue; if (obj != null) { value = obj.toString(); } else { value = String.valueOf(x.intValue); } break; } sb.append(value); sb.append(']'); } } if (printType) { if (jsType != null) { String jsTypeString =

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> jsType.toString(); if (jsTypeString != null) { sb.append(" : "); sb.append(jsTypeString); } } } } } public String toStringTree() { return toStringTreeImpl(); } private String toStringTreeImpl() { try { StringBuffer s = new StringBuffer(); appendStringTree(s); return s.toString(); } catch (IOException e) { throw new RuntimeException("Should not happen\n" + e); } } public void appendStringTree(Appendable appendable) throws IOException { toStringTreeHelper(this, 0, appendable); } private static void toStringTreeHelper(Node n, int level, Appendable sb) throws IOException { if (Token.printTrees) { for (int i = 0; i != level; ++i) { sb.append(" "); } sb.append(n.toString()); sb.append('\n'); for (Node cursor = n.getFirstChild(); cursor != null; cursor = cursor.getNext()) { toStringTreeHelper(cursor, level + 1, sb); } } } int type; // type of the node; Token.NAME for example Node next; // next sibling private Node first; // first element of a linked list of children private Node last; // last element of a linked list of children /** * Linked list of properties. Since vast majority of nodes would have * no more then 2 properties, linked list saves memory and provides * fast lookup. If this does not holds, propListHead can be replaced * by UintMap. */ private PropListItem propListHead; /** * COLUMN_BITS represents how many of the lower-order bits of * sourcePosition are reserved for storing the column number. * Bits above these store the line number. * This gives us decent position information for everything except * files already passed through a minimizer, where lines might * be longer than 4096 characters. */ public static final int COLUMN_BITS = 12; /** * MAX_COLUMN_NUMBER represents the maximum column number that can * be represented. JSCompiler's modifications to Rhino cause all * tokens located beyond the maximum column to

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> case Token.CONTINUE: return "continue"; case Token.VAR: return "var"; case Token.WITH: return "with"; case Token.CATCH: return "catch"; case Token.FINALLY: return "finally"; case Token.RESERVED: return "reserved"; case Token.NOT: return "not"; case Token.VOID: return "void"; case Token.BLOCK: return "block"; case Token.ARRAYLIT: return "arraylit"; case Token.OBJECTLIT: return "objectlit"; case Token.LABEL: return "label"; case Token.TARGET: return "target"; case Token.LOOP: return "loop"; case Token.EXPR_VOID: return "expr_void"; case Token.EXPR_RESULT: return "expr_result"; case Token.JSR: return "jsr"; case Token.SCRIPT: return "script"; case Token.EMPTY: return "empty"; case Token.GET_REF: return "get_ref"; case Token.REF_SPECIAL: return "ref_special"; } return "<unknown="+token+">"; } /** Returns true if this node is equivalent semantically to another */ public boolean isEquivalentTo(Node node) { if (type == Token.ARRAYLIT) { try { int[] indices1 = (int[])getProp(Node.SKIP_INDEXES_PROP); int[] indices2 = (int[])node.getProp(Node.SKIP_INDEXES_PROP); if (indices1 == null) { if (indices2 != null) return false; } else if (indices2 == null) { return false; } else if (indices1.length != indices2.length) { return false; } else { for (int i = 0; i < indices1.length; i++) { if (indices1[i] != indices2[i]) return false; } } } catch (Exception e) { return false; } } else if (type == Token.INC || type == Token.DEC) { int post1 = this.getIntProp(INCRDECR_PROP, 0); int post2 =

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>.VOID_TYPE)); register(getNativeType(JSTypeNative.VOID_TYPE), "Undefined"); register(getNativeType(JSTypeNative.VOID_TYPE), "void"); register(getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE), "Function"); } private void register(JSType type) { register(type, type.toString()); } private void register(JSType type, String name) { namesToTypes.put(name, type); // Add all the namespaces in which this name lives. while (name.indexOf('.') > 0) { name = name.substring(0, name.lastIndexOf('.')); namespaces.add(name); } } private void registerNativeType(JSTypeNative typeId, JSType type) { nativeTypes[typeId.ordinal()] = type; } /** * Tells the type system that {@code owner} may have a property named * {@code propertyName}. This allows the registry to keep track of what * types a property is defined upon. * * This is NOT the same as saying that {@code owner} must have a property * named type. ObjectType#hasProperty attempts to minimize false positives * ("if we're not sure, then don't type check this property"). The type * registry, on the other hand, should attempt to minimize false negatives * ("if this property is assigned anywhere in the program, it must * show up in the type registry"). */ public void registerPropertyOnType(String propertyName, ObjectType owner) { Set<ObjectType> typeSet = typesIndexedByProperty.get(propertyName); if (typeSet == null) { typesIndexedByProperty.put(propertyName, typeSet = Sets.newHashSet()); } greatestSubtypeByProperty.remove(propertyName); typeSet.add(owner); } /** * Gets the greatest subtype of the {@code type} that has a property * {@code propertyName} defined on it. */ public JSType getGreatestSubtypeWithProperty( JSType type, String propertyName) { if (greatestSubtypeByProperty.containsKey(propertyName)) { return greatestSubtypeByProperty.get(propertyName) .getGreatestSubtype(type); } if (typesIndexedByProperty.containsKey(propertyName)) {

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>ToImplementors.put(interfaceInstance.getReferenceName(), type); } /** * Returns a collection of types that directly implement {@code * interfaceInstance}. Subtypes of implementing types are not guaranteed to * be returned. {@code interfaceInstance} must be an ObjectType for the * instance of the interface. */ public Collection<FunctionType> getDirectImplementors( ObjectType interfaceInstance) { return interfaceToImplementors.get(interfaceInstance.getReferenceName()); } /** * Records declared type names. Given the limited scopes of JavaScript, all * named types are dumped in a common global scope. We may need to revise this * assumption in the future. * * @param name The name of the type to be recorded. * @param t The actual type being associated with the name. * @return True if this name is not already defined, false otherwise. */ public boolean declareType(String name, JSType t) { if (namesToTypes.containsKey(name)) { return false; } register(t, name); return true; } /** * Records a forward-declared type name. We will not emit errors if this * type name never resolves to anything. */ public void forwardDeclareType(String name) { forwardDeclaredTypes.add(name); } /** * Whether this is a forward-declared type name. */ public boolean isForwardDeclaredType(String name) { return forwardDeclaredTypes.contains(name); } /** Determines whether the given JS package exists. */ public boolean hasNamespace(String name) { return namespaces.contains(name); } /** * Looks up a type by name. * * @param jsTypeName The name string. * @return the corresponding JSType object or {@code null} it cannot be found */ public JSType getType(String jsTypeName) { // TODO(user): Push every local type name out of namesToTypes so that // NamedType#resolve is correct. if (jsTypeName.equals(templateTypeName)) { return templateType; } return namesToTypes.get(jsTypeName); } public JSType getNativeType(JSTypeNative typeId) { return nativeTypes[typeId.ordinal()]; } public ObjectType getNative

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> The last element of this array * is considered a variable length argument. * @return a tree hierarchy representing a typed argument list. */ public Node createParametersWithVarArgs(JSType... parameterTypes) { return createParameters(true, parameterTypes); } /** * Creates a tree hierarchy representing a typed parameter list in which * every parameter is optional. */ public Node createOptionalParameters(JSType... parameterTypes) { FunctionParamBuilder builder = new FunctionParamBuilder(this); builder.addOptionalParams(parameterTypes); return builder.build(); } /** * Creates a tree hierarchy representing a typed argument list. * * @param lastVarArgs whether the last type should considered as a variable * length argument. * @param parameterTypes the parameter types. The last element of this array * is considered a variable length argument is {@code lastVarArgs} is * {@code true}. * @return a tree hierarchy representing a typed argument list */ private Node createParameters(boolean lastVarArgs, JSType... parameterTypes) { FunctionParamBuilder builder = new FunctionParamBuilder(this); int max = parameterTypes.length - 1; for (int i = 0; i <= max; i++) { if (lastVarArgs && i == max) { builder.addVarArgs(parameterTypes[i]); } else { builder.addRequiredParams(parameterTypes[i]); } } return builder.build(); } /** * Creates a function type. * @param returnType the function's return type * @param lastVarArgs whether the last parameter type should be considered as * an extensible var_args parameter * @param parameterTypes the parameters' types */ public FunctionType createFunctionType(JSType returnType, boolean lastVarArgs, JSType... parameterTypes) { if (lastVarArgs) { return createFunctionTypeWithVarArgs(returnType, parameterTypes); } else { return createFunctionType(returnType, parameterTypes); } } /** * Creates a new function type based on an existing function type but * with a new return type. * @param existingFunctionType the existing function type. * @param returnType the new return type. */ public FunctionType createFunctionTypeWithNewReturnType( Function

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> true, false); } /** * Creates an interface function type. * @param name the function's name * @param source the node defining this function. Its type * ({@link Node#getType()}) must be {@link Token#FUNCTION}. */ public FunctionType createInterfaceType(String name, Node source) { return new FunctionType(this, name, source); } /** * Creates a parameterized type. */ public ParameterizedType createParameterizedType( ObjectType objectType, JSType parameterType) { return new ParameterizedType(this, objectType, parameterType); } /** * Identifies the name of an enum before we actually declare it. */ public void identifyEnumName(String name) { enumTypeNames.add(name); } /** * Creates a RecordType from the nodes representing said record type. * @param n The node with type info. * @param sourceName The source file name. * @param scope A scope for doing type name lookups. */ public JSType createRecordTypeFromNodes(Node n, String sourceName, StaticScope<JSType> scope) { RecordTypeBuilder builder = new RecordTypeBuilder(this); // For each of the fields in the record type. for (Node fieldTypeNode = n.getFirstChild(); fieldTypeNode != null; fieldTypeNode = fieldTypeNode.getNext()) { // Get the property's name. Node fieldNameNode = fieldTypeNode; boolean hasType = false; if (fieldTypeNode.getType() == Token.COLON) { fieldNameNode = fieldTypeNode.getFirstChild(); hasType = true; } String fieldName = fieldNameNode.getString(); // TODO(user): Move this into the lexer/parser. // Remove the string literal characters around a field name, // if any. if (fieldName.startsWith("'") || fieldName.startsWith("\"")) { fieldName = fieldName.substring(1, fieldName.length() - 1); } // Get the property's type. JSType fieldType = null; if (hasType) { // We have a declared type. fieldType = createFromTypeNodes( fieldTypeNode.getLastChild(), sourceName, scope); } else { // Otherwise, the type is UNKNOWN. fieldType =

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> code will only run checks and not optimizations. */ abstract protected List<PassFactory> getChecks(); /** * Gets the optimization passes to run. * * Optimization passes revolve around producing smaller and faster code. * They should always run after checking passes. */ abstract protected List<PassFactory> getOptimizations(); /** * Gets a graph of the passes run. For debugging. */ GraphvizGraph getPassGraph() { LinkedDirectedGraph<String, String> graph = LinkedDirectedGraph.create(); Iterable<PassFactory> allPasses = Iterables.concat(getChecks(), getOptimizations()); String lastPass = null; String loopStart = null; for (PassFactory pass : allPasses) { String passName = pass.getName(); int i = 1; while (graph.hasNode(passName)) { passName = pass.getName() + (i++); } graph.createNode(passName); if (loopStart == null && !pass.isOneTimePass()) { loopStart = passName; } else if (loopStart != null && pass.isOneTimePass()) { graph.connect(lastPass, "loop", loopStart); loopStart = null; } if (lastPass != null) { graph.connect(lastPass, "", passName); } lastPass = passName; } return graph; } /** * Create a type inference pass. */ final TypeInferencePass makeTypeInference(AbstractCompiler compiler) { return new TypeInferencePass( compiler, compiler.getReverseAbstractInterpreter(), topScope, typedScopeCreator); } /** * Create a type-checking pass. */ final TypeCheck makeTypeCheck(AbstractCompiler compiler) { return new TypeCheck( compiler, compiler.getReverseAbstractInterpreter(), compiler.getTypeRegistry(), topScope, typedScopeCreator, options.reportMissingOverride, options.reportUnknownTypes) .reportMissingProperties(options.enables( DiagnosticGroup.forType(TypeCheck.INEXISTENT_PROPERTY))); } final static void addPassFactoryBefore( List<PassFactory> factoryList, PassFactory factory, String passName) { for (int i = 0; i

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> < factoryList.size(); i++) { if (factoryList.get(i).getName().equals(passName)) { factoryList.add(i, factory); return; } } throw new IllegalArgumentException( "No factory named '" + passName + "' in the factory list"); } /** * Find the first pass provider that does not have a delegate. */ final PassConfig getBasePassConfig() { PassConfig current = this; while (current instanceof PassConfigDelegate) { current = ((PassConfigDelegate) current).delegate; } return current; } /** * Get intermediate state for a running pass config, so it can * be paused and started again later. */ abstract State getIntermediateState(); /** * Set the intermediate state for a pass config, to restart * a compilation process that had been previously paused. */ abstract void setIntermediateState(State state); /** * An implementation of PassConfig that just proxies all its method calls * into an inner class. */ static class PassConfigDelegate extends PassConfig { private final PassConfig delegate; PassConfigDelegate(PassConfig delegate) { super(delegate.options); this.delegate = delegate; } @Override protected List<PassFactory> getChecks() { return delegate.getChecks(); } @Override protected List<PassFactory> getOptimizations() { return delegate.getOptimizations(); } @Override ScopeCreator getScopeCreator() { return delegate.getScopeCreator(); } @Override Scope getTopScope() { return delegate.getTopScope(); } @Override State getIntermediateState() { return delegate.getIntermediateState(); } @Override void setIntermediateState(State state) { delegate.setIntermediateState(state); } } /** * Intermediate state for a running pass configuration. */ static class State implements Serializable { private static final long serialVersionUID = 1L; final Map<String, Integer> cssNames; final Set<String> exportedNames; final CrossModuleMethodMotion.IdGenerator crossModuleIdGenerator; final VariableMap variableMap; final VariableMap propertyMap; final VariableMap anonymousFunctionNameMap; final FunctionNames functionNames; State(Map<String, Integer> cssNames,

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS>.kind = Kind.INTERFACE; this.typeOfThis = new InstanceObjectType(registry, this); } @Override public boolean isInstanceType() { // The universal constructor is its own instance, bizarrely. return equals(registry.getNativeType(U2U_CONSTRUCTOR_TYPE)); } @Override public boolean isConstructor() { return kind == Kind.CONSTRUCTOR; } @Override public boolean isInterface() { return kind == Kind.INTERFACE; } @Override public boolean isOrdinaryFunction() { return kind == Kind.ORDINARY; } @Override public boolean isFunctionType() { return true; } @Override public boolean canBeCalled() { return true; } public Iterable<Node> getParameters() { Node n = getParametersNode(); if (n != null) { return n.children(); } else { return Collections.emptySet(); } } /** Gets an LP node that contains all params. May be null. */ public Node getParametersNode() { return call == null ? null : call.parameters; } /** Gets the minimum number of arguments that this function requires. */ public int getMinArguments() { // NOTE(nicksantos): There are some native functions that have optional // parameters before required parameters. This algorithm finds the position // of the last required parameter. int i = 0; int min = 0; for (Node n : getParameters()) { i++; if (!n.isOptionalArg() && !n.isVarArgs()) { min = i; } } return min; } /** * Gets the maximum number of arguments that this function requires, * or Integer.MAX_VALUE if this is a variable argument function. */ public int getMaxArguments() { Node params = getParametersNode(); if (params != null) { Node lastParam = params.getLastChild(); if (lastParam == null || !lastParam.isVarArgs()) { return params.getChildCount(); } } return Integer.MAX_VALUE; } public JSType getReturnType() { return call == null ? null : call.returnType; } /** * Gets the {@code prototype}

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> property of this function type. This is * equivalent to {@code (ObjectType) getPropertyType("prototype")}. */ public FunctionPrototypeType getPrototype() { // lazy initialization of the prototype field if (prototype == null) { setPrototype(new FunctionPrototypeType(registry, this, null)); } return prototype; } /** * Sets the prototype, creating the prototype object from the given * base type. * @param baseType The base type. */ public void setPrototypeBasedOn(ObjectType baseType) { if (prototype == null) { setPrototype( new FunctionPrototypeType( registry, this, baseType, isNativeObjectType())); } else { prototype.setImplicitPrototype(baseType); } } /** * Sets the prototype. * @param prototype the prototype. If this value is {@code null} it will * silently be discarded. */ public boolean setPrototype(FunctionPrototypeType prototype) { if (prototype == null) { return false; } // getInstanceType fails if the function is not a constructor if (isConstructor() && prototype == getInstanceType()) { return false; } this.prototype = prototype; if (isConstructor() || isInterface()) { FunctionType superClass = getSuperClassConstructor(); if (superClass != null) { superClass.addSubType(this); } } return true; } /** * Returns all interfaces implemented by a class or its superclass and any * superclasses for any of those interfaces. If this is called before all * types are resolved, it may return an incomplete set. */ public Iterable<ObjectType> getAllImplementedInterfaces() { Set<ObjectType> interfaces = Sets.newHashSet(); for (ObjectType type : getImplementedInterfaces()) { addRelatedInterfaces(type, interfaces); } return interfaces; } private void addRelatedInterfaces(ObjectType instance, Set<ObjectType> set) { FunctionType constructor = instance.getConstructor(); if (constructor != null) { if (!constructor.isInterface()) { return; } set.add(instance); if (constructor.getSuperClassConstructor() != null) { addRelatedInterfaces( constructor.getSuperClassConstructor().getInstanceType(), set); } } } /** Returns interfaces

Closure, 140

<FILEB>
<CHANGES>
fillEmptyModules(modules);
<CHANGEE>
<CHANGES>
private void fillEmptyModules(JSModule[] modules) {
for (int i = 1; i < modules.length; i ++) {
JSModule module = modules[i];
if (module.getInputs().isEmpty()) {
module.add(JSSourceFile.fromCode("[" + module.getName() + "]", ""));
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<FILEE>
<FILEB> this.externs = makeCompilerInput(externs, true); this.modules = null; this.moduleGraph = null; this.inputs = makeCompilerInput(inputs, false); initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { initOptions(options); checkFirstModule(modules); <CHANGES> <CHANGEE> this.externs = makeCompilerInput(externs, true); this.modules = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { this.moduleGraph = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } /** * Fill any empty modules with a place holder file. It makes any cross module * motion easier. */ <CHANGES> <CHANGEE> static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot<SCANS> * Gets the source node or null if this is an unknown function. */ public Node getSource() { return source; } /** * Sets the source node. */ public void setSource(Node source) { this.source = source; } /** Adds a type to the list of subtypes for this type. */ private void addSubType(FunctionType subType) { if (subTypes == null) { subTypes = Lists.newArrayList(); } subTypes.add(subType); } /** * Returns a list of types that are subtypes of this type. This is only valid * for constructor functions, and may be null. This allows a downward * traversal of the subtype graph. */ public List<FunctionType> getSubTypes() { return subTypes; } @Override public boolean hasCachedValues() { return prototype != null || super.hasCachedValues(); } /** * Gets the template type name. */ public String getTemplateTypeName() { return templateTypeName; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { call = (ArrowType) safeResolve(call, t, scope); prototype = (FunctionPrototypeType) safeResolve(prototype, t, scope); typeOfThis = (ObjectType) safeResolve(typeOfThis, t, scope); boolean changed = false; ImmutableList.Builder<ObjectType> resolvedInterfaces = ImmutableList.builder(); for (ObjectType iface : implementedInterfaces) { ObjectType resolvedIface = (ObjectType) iface.resolve(t, scope); resolvedInterfaces.add(resolvedIface); changed |= (resolvedIface != iface); } if (changed) { implementedInterfaces = resolvedInterfaces.build(); } if (subTypes != null) { for (int i = 0; i < subTypes.size(); i++) { subTypes.set(i, (FunctionType) subTypes.get(i).resolve(t, scope)); } } return super.resolveInternal(t, scope); } }